The Deadline That Made Me Rethink My Architecture: Building Timesheetflow with Domain Thinking

Published: (January 4, 2026 at 08:58 AM EST)
5 min read
Source: Dev.to

Source: Dev.to

That one question changed how I approached what I initially thought was “just Excel processing.”
I was building Timesheetflow—a small system to automate monthly employee timesheets that are still submitted as Excel files (because, realistically, many teams still live in spreadsheets).

The Real Workflow (What the Business Actually Does)

Timesheetflow’s workflow is simple—and very real:

  1. Admin sets a processing deadline (usually month‑end).
  2. Employees upload their own monthly timesheet to a Google Drive folder before the deadline (submissions are for the current month only).
  3. At the deadline, the system processes timesheets one by one.
  4. Approvers review and approve one, many, or all timesheets.
    • Late submissions are allowed but clearly marked Late.
  5. Admin downloads an Excel salary summary for that month.

When I wrote it down like this, I realized something:

This isn’t an “Excel automation” problem.
This is a monthly payroll close problem.

What I Thought the Problem Was

My first approach was very implementation‑driven:

  • “There’s a Drive folder.”
  • “There are Excel files.”
  • “I need to parse and export.”

So my architecture naturally became a pipeline:

  • Drive client downloads files
  • A parser extracts rows
  • A validator checks columns
  • An exporter builds a consolidated report

It looked clean… but the code kept reading like:

“update tables, move files, generate output”

instead of:

“close the month, enforce the deadline, approve submissions, finalize payroll”

That difference sounds subtle, but it changes everything—especially when requirements evolve.

What I Realized Afterward

Good architecture isn’t just about layers and patterns.
It’s about meaning.

The moment I treated the month‑end workflow as a domain (instead of a batch job), the design got clearer:

  • A deadline isn’t a timestamp field—it’s a rule that changes system behavior.
  • “Late” isn’t a warning label—it affects approval visibility and auditability.
  • “Latest submission wins” isn’t a query trick—it’s a policy the business depends on.

The Ubiquitous Language I Started Using

Once I stopped thinking in “files” and started thinking in “business”, the vocabulary became obvious:

TermMeaning
Monthly Run / Payroll PeriodThe month being closed
DeadlineThe cutoff time
Timesheet SubmissionOne employee’s monthly entry
Late SubmissionAllowed, but flagged
Latest Submission WinsPolicy when employees upload multiple versions
ApprovalApprove/reject; bulk approve valid
Salary Summary ExportThe admin deliverable

When your code uses this language, you don’t need long comments to explain what it does.

Before vs. After (Pipeline Thinking vs. Domain Thinking)

Before: “Process files”

// Pipeline mindset: process whatever is in the folder
var files = drive.ListXlsxFiles(folderId);

foreach (var file in files)
{
    var rows = ParseExcel(file);
    Validate(rows);
    Save(rows);
}

ExportSalarySummary();

It works—but it hides the real rules:

  • Which month is this?
  • Is the deadline enforced?
  • Which file wins if an employee uploads twice?
  • What happens after approval?

After: “Close a monthly run”

// Domain mindset: close a payroll period with explicit rules
run.LockAtDeadline(now);

run.RefreshSubmissionsFromDrive();   // latest submission wins
run.FlagLateSubmissions();           // uploaded after deadline

foreach (var submission in run.ActiveSubmissions())
{
    submission.ValidateCurrentMonthOnly();
}

approvals.ApproveAllValid(run);      // late is a badge, invalid blocks approval

var report = payroll.ExportSalarySummary(run); // Excel for admin

Now the code reads like the business process:

  • lock the period
  • evaluate submissions under known rules
  • approve what’s valid
  • export the payroll summary

That shift made everything easier to maintain and explain.

Key Domain Rules (That Matter More Than Excel)

  1. Current month only – Employees can submit timesheets for the active month only.
  2. Deadline locks the run – At the deadline, the run transitions into a “locked” phase for processing.
  3. Late submissions are allowed, but flagged – After the deadline, submissions are marked Late and stay visible in approval/export.
  4. Latest submission wins – If an employee uploads multiple timesheets for the same month:
    • the system uses the most recent file (by Drive timestamps)
    • older ones are marked superseded
  5. Invalid beats late – If a timesheet is invalid, it’s invalid—whether it’s late or not.
    • Late is a badge.
    • Invalid is a blocker.
  6. Salary export is the admin deliverable – The end result is not “processed rows”; it’s a monthly Excel summary that payroll/admin can use.

Implementation Notes (Tech Stack)

Timesheetflow is built with:

  • ASP.NET Core (.NET 8) – Web + API
  • Hangfire – Deadline scheduling and background processing
  • ClosedXML – Excel parsing/export
  • Google Drive – Submission channel (Workspace folder + service‑account access)

Even with a simple stack, modeling the domain clearly made the system feel “product‑like” instead of “script‑like”.

Key Takeaways

  • This wasn’t really an Excel problem—it was a month‑end payroll close problem.
  • Deadlines, late flags, and “latest submission wins” are domain rules, not just utility logic.
  • Building a ubiquitous language around those rules yields code that reads like the business process, making maintenance and future changes far easier.

When Code Mirrors the Business Language

  • When code mirrors the business language, it becomes easier to read, test, and extend.
  • The best architecture doesn’t just run—it communicates intent.

Closing Thoughts

I started Timesheetflow thinking I was building an Excel automation tool.
The real value came when I stopped designing around files and started designing around the workflow the business lives by every month.

If you’ve ever had a moment where a “simple automation” turned out to be a domain problem in disguise, I’d love to hear about it.

Connect with Me

  • GitHub:
  • LinkedIn:

If you’d like, I can also share:

  • A minimal domain model (MonthlyRun, TimesheetSubmission, Approval) for .NET 8
  • A Hangfire job layout for the deadline + processing pipeline
  • An example Salary_Summary.xlsx structure (ByEmployee / Details / Exceptions)

Just let me know whether you want the article to include code that compiles (full sample classes) or keep it at conceptual snippets like this post.

Back to Blog

Related posts

Read more »

Let's separate the separation

Introduction During the last days of 2025, our team lead took an extra day off and missed an important meeting. After a recent restructure, one colleague left...