Help & Documentation

Introduction

Overview

The Expense Management System is a web-based platform designed to streamline the process of submitting, approving, paying, and reconciling expense claims within organizations. It supports multiple companies, role-based access, and integrates with external services for notifications and security.

The system is intended for:

  • Employees who need to submit expense claims
  • Approvers and payers who review and process claims
  • Company administrators who manage users and settings

Key Features

  • Multi-company support: Users can belong to one or more companies, each with its own claims and user management.
  • Role-based access control: Permissions are managed by assigning roles (Owner, Approver, Payer, etc.) to users per company.
  • Expense claim workflow: Submit, approve/reject, pay, and reconcile claims with full audit trails.
  • Document attachment: Upload receipts and supporting files to claims.
  • Telegram bot integration: Receive notifications and link your account for secure updates.
  • Invite links: Easily onboard new users via company-specific invite URLs.
  • Audit and activity logging: All actions are tracked for transparency and compliance.
  • Responsive design: Works on desktop and mobile devices.

Getting Started

Accessing the Website

  • Open your web browser (Chrome, Edge, Firefox, Safari recommended).
  • Enter the website URL provided by your company administrator.
  • The site is responsive and works on both desktop and mobile devices.

Logging In

  • On the login page, enter your credentials.
  • You may log in using:
    • Local login (email selection, no password required for test/demo accounts)
    • External providers (Auth0, Google, Microsoft, etc.)
  • If you forget your login method, contact your company administrator.

User Registration

  • New users can register via an invite link sent by a company administrator.
  • Click the invite link and follow the registration steps.
  • Fill in your name, email, and any required details.
  • Some companies may use external authentication providers; follow the prompts as needed.
  • After registration, you may be assigned roles and linked to one or more companies.

User Profile Management

Viewing and Editing Profile

  1. Access your profile from the navigation menu.
  2. View your name, email, authentication provider, and assigned companies.
  3. Edit your first and last name if allowed (some external providers may restrict editing).
  4. Save changes to update your profile.

Linking Telegram Bot

  1. On your profile page copy the 5- or 6-character "Telegram code" shown.
  2. Open Telegram and start the Expense bot (send /start).
  3. When the bot prompts, paste the code you copied from your profile page.
  4. The bot will confirm when your account is linked. Once linked, you will receive notifications for claim status changes and approvals.

Company Management

Viewing Company Details

  1. Access company information from the dashboard or company menu.
  2. View company name, users, and categories.

Managing Users and Roles

  1. Owners can assign roles (Approver, Payer, etc.) to users.
  2. Activate or deactivate users as needed.
  3. Use the Manage Users page to view bot link status and change roles.
  4. Filter and search users by name, role, or status.

Inviting New Users

  1. Generate an invite link from the Manage Users page.
  2. Copy and share the link with new users to onboard them.
  3. New users follow the link to register and join the company.

Main Pages & Workflows

Oversee Page

Purpose: Monitor all expense claims for your company, filter/search, and view summary statistics.

How to Use:

  1. Navigate to the Oversee page from the main menu.
  2. Use the filter controls (category, subcategory, status, date, user) to narrow down claims.
  3. Claims are shown in a responsive table (desktop) or card view (mobile).
  4. Click a claim to view details, including creator, category, and status.
  5. Use sorting and search to quickly find specific claims.

Approve Page

Purpose: Review submitted claims, approve or reject, and view audit logs.

How to Use:

  1. Go to the Approve page.
  2. Filter claims by category, subcategory, or user.
  3. Review each claim in the table or card view.
  4. Click a claim to open the Approve View.
  5. In Approve View, review details and receipts.
  6. Click "Approve" to approve, or "Reject" to open a modal and enter a rejection reason.
  7. Actions are logged for audit purposes.

Pay Page

Purpose: Mark claims as paid, change categories, and view payment history.

How to Use:

  1. Open the Pay page.
  2. Filter and search for claims ready for payment.
  3. Click a claim to open the Pay View.
  4. Review claim details and receipts.
  5. Click "Mark as Paid" to record payment.
  6. Optionally, click "Change Category" to update claim category/subcategory.
  7. Use the "Reject Claim" button if payment is not possible, providing a reason.

Reconcile Page

Purpose: Finalize claims after payment and resolve discrepancies.

How to Use:

  1. Go to the To Reconcile or Reconciled page.
  2. Filter claims by category, subcategory, or user.
  3. Click a claim to open the Reconcile View.
  4. Review payment details and mark the claim as reconciled.
  5. Use audit logs to track reconciliation actions.

Submit Page

Purpose: Create and submit new expense claims.

How to Use:

  1. Click "Add New Claim" on the Expense Claims History page.
  2. Fill in claim details: date, title, category, amount, description.
  3. Add expense lines and upload receipts.
  4. Save as draft or submit for approval.
  5. Track status from draft to submitted.

Manage Users Page

Purpose: Assign roles, activate/deactivate users, and check bot link status.

How to Use:

  1. Open Manage Users from the company menu.
  2. View all users in a scrollable, filterable table.
  3. Filter by role, status, or search by name.
  4. Assign roles using checkboxes.
  5. Activate/deactivate users with the status button.
  6. See "Bot linked" badge for users with Telegram integration.
  7. Copy and share invite links for onboarding.

Profile Page

Purpose: Edit personal details, link Telegram, and view assigned companies.

How to Use:

  1. Access your profile from the navigation menu.
  2. View and edit your name (if allowed), email, and provider.
  3. Enter your Telegram username and follow instructions to link the bot.
  4. View assigned companies and bot link status.
  5. Save changes to update your profile.

Login/Register Pages

Purpose: Authenticate and onboard users.

How to Use:

  1. Go to the login page and select your login method (local or external).
  2. For registration, use the invite link provided by your company.
  3. Complete the registration form and follow prompts for external providers.
  4. After registration, log in and access your assigned companies.

Dashboard/Home Page

Purpose: Overview of user and company activity, quick actions.

How to Use:

  1. View summary cards for total claims, amounts, pending, and approved.
  2. Access quick links to submit claims, manage users, or view company details.
  3. See recent notifications and activity.

Expense Claims

Creating a New Expense Claim

  1. Go to the Submit page and click 'New Claim'.
  2. Fill in the claim details: title, amount, category, description, and claim date.
  3. Add expense lines for each item or receipt.
  4. Upload receipts and supporting documents (PDF, JPG, PNG, etc.).
  5. Save as draft or submit for approval.

Attaching Receipts

  1. In the claim form, use the upload section to attach files.
  2. Supported file types are listed; ensure your files meet requirements.
  3. Uploaded files are shown in the claim details.

Editing and Submitting Claims

  1. Edit any draft claim by clicking its row in the claims history.
  2. Update details or add/remove expense lines and receipts.
  3. Click 'Submit' to send the claim for approval.

Viewing Claim Status

  1. Track your claim's progress from draft to submitted, approved, paid, and reconciled.
  2. Status is shown in the claims history and on each claim's detail page.
  3. View rejection reasons if a claim is rejected.

Approvals Workflow

Reviewing Claims

  1. Approvers see claims awaiting their review on the Approve page.
  2. Click a claim to view its details and attached receipts.
  3. Use filters to narrow down claims by category, user, or date.

Approving or Rejecting

  1. In the Approve View, review all claim details and receipts.
  2. Click 'Approve' to approve the claim.
  3. Click 'Reject' to open a modal and enter a rejection reason.
  4. Submit the rejection; the claim status updates and the submitter is notified.

Notifications and Audit Logs

  1. All actions (approve, reject) are logged for transparency.
  2. Users receive notifications for approvals, rejections, and status changes via the Telegram bot when linked. Email notifications are optional and may require additional configuration.
  3. Approvers (and system owners) can send a "nudge" to remind approvers about pending claims — this uses the same Telegram notification path.
  4. Audit logs can be viewed by authorized users (Owners and Overseers) for compliance.

Payments

Marking Claims as Paid

  1. On the Pay page, select claims ready for payment.
  2. Click a claim to open its details.
  3. Click 'Mark as Paid' and enter payment details if required.
  4. The claim status updates to 'Paid'.

Changing Categories/Subcategories

  1. In the Pay View, click 'Change Category' to open the modal.
  2. Select the new category and subcategory.
  3. Save changes to update the claim.

Viewing Payment History

  1. View all paid claims on the Paid or Reconciled pages.
  2. Filter by date, user, or category to find specific payments.
  3. Payment details are shown in each claim's history.

Security and Access Control

User Roles and Permissions

  1. Roles include Owner, Approver, Payer, Reconciler, Submitter, Overseer, Global Approver.
  2. Each role grants specific permissions for claims and company management.
  3. Owners can assign and change roles for other users.

Company-Level Access

  1. Users only see claims and data for companies they are assigned to.
  2. Owners manage user access and roles from the Manage Users page.
  3. Access to claims, approvals, and payments is restricted by role and company.

Notifications and Integrations

Telegram Bot Integration

  1. On your profile page copy the 5- or 6-character Telegram code displayed.
  2. Open the Expense bot in Telegram and send /start.
  3. When prompted by the bot, paste the code from your profile page to link your account.
  4. Once linked, you'll receive instant notifications for claim submissions, approvals, rejections and other status changes.

Troubleshooting and Support

Common Issues

  • Can't log in: Check your credentials or contact your administrator.
  • Can't submit claim: Ensure all required fields are filled and receipts are attached.
  • Missing notifications: Check Telegram/email setup.
  • Role or access problems: Contact your company owner or admin.

Contacting Support

  1. Use the support contact provided by your company.
  2. Include details and screenshots if possible.
  3. For technical issues, provide error messages and steps to reproduce.

System Settings and Configuration

Application Settings

  1. Admins can manage system-wide settings from the admin panel.
  2. Configure company details, categories, and user roles.
  3. Update environment-specific settings as needed.

Audit and Activity Logs

Viewing Action Logs

  1. Access audit logs from the Audit page on the company dashboard.
  2. Filter logs by user, date, or action type to find specific events.
  3. Use logs to review claim actions, approvals, payments, and changes.
  4. In this implementation only users with the Owner or Overseer role can view audit logs.

Understanding Audit Trails

  1. Audit trails show who performed each action and when; audit entries are recorded when key actions occur (approvals, rejections, category changes, etc.).
  2. Use logs for compliance, troubleshooting, and transparency.
  3. Only authorized users (Owners and Overseers) can view audit logs in the current system.

Date/Time Usage Report

This report summarizes all occurrences of date/time usage across the Website project and nearby helper/test tooling. Goal: identify whether times are stored/used as UTC or local, how local conversion is performed, and highlight places to standardize for correct local displays and system-wide usage abroad.

Scan scope: searched for DateTime, DateTimeOffset, UtcNow, Now(, ToLocalTime, ToUniversalTime, DateTimeKind, TimeZoneInfo, getTimezoneOffset, Intl.DateTimeFormat, and related patterns in Website.

Summary

  • Total obvious application hits found: many; a focused set is listed in the table below (pages/services/models/partials).
  • Common patterns:
    • Audit/log timestamps are recorded with DateTime.UtcNow (good).
    • Some request/user-visible timestamps are generated with DateTime.Now or DateTime.Today (local machine time) — inconsistent with UTC storage.
    • Several places render DateTime to strings directly in Razor views; some explicitly call ToLocalTime() while others assume DateTime is already local or UTC.
    • JSON parsing and UI form handling frequently uses DateTime.TryParse without specifying culture or kind; parsed DateTime.Kind will be Unspecified.
    • File system timestamps use FileInfo.CreationTime which returns local time; no explicit UTC calls.

Recommendations (high level)

  • Standardize on storing all server-side timestamps in UTC (use DateTime.UtcNow or DateTimeOffset.UtcNow) and persist with an explicit kind (prefer DateTimeOffset for DB fields that cross timezones).
  • When accepting user-entered dates (date-only fields), treat them as local to the user’s browser and convert to UTC for storage using the user's timezone offset sent from client-side, or keep as local-date semantics where appropriate (e.g., LineDate representing day of spend).
  • For displaying times in the UI: convert UTC times to the browser locale/timezone (client-side JS) or server-side using a known timezone per user (stored preference) and format accordingly. Avoid ToLocalTime() unless the server's local timezone is the desired display timezone.
  • When parsing date strings in C#, prefer DateTime.ParseExact with the expected format and DateTimeStyles.AssumeUniversal / AssumeLocal as appropriate, or parse to DateTimeOffset.

Detailed table

| Page / File | Function / Location | Purpose | Stored As (UTC/local) | How Local Determined / Notes | |---|---|---:|---:|---| | Services/ActionLogService.cs | LogAsync, AddAuditAsync | Record action and audit logs | UTC (DateTime.UtcNow) | Stored explicitly with UtcNow. Views sometimes call ToLocalTime() before display. Good practice for storage. | | Pages/Shared/_AuditLogPartial.cshtml | Razor partial rendering AuditLog list | Display audit timestamp in UI | Audit stored UTC | Calls @log.DateTime.ToLocalTime().ToString(...) to display server-local time — this converts UTC to server local timezone, not the user's timezone. If users abroad use app, times will display in server timezone. | | Pages/SysAdmin/ToggleMaintenance.cshtml.cs | OnGet populates ActiveUsers | Show users active in last 30 minutes | Uses DateTime.UtcNow for cutoff; ActiveUsers contains LastLoginAt (Utc) | The tuple stores DateTime values (UTC); view shows difference using DateTime.UtcNow - u.Item2 in a view: ToggleMaintenance.cshtml uses DateTime.UtcNow - u.Item2 and prints seconds/minutes ago — consistent. | | Pages/SysAdmin/ToggleMaintenance.cshtml | UI shows activity age | Display "seconds/minutes ago" | Uses DateTime.UtcNow - u.Item2 | Calculation happens in server using UTC. Display reflects server-time difference — OK, but user timezone not used. | | Services/TemporaryFileCleanupService.cs | CleanupTemporaryFilesAsync, GetTemporaryFileStatsAsync | Delete files older than X hours using file creation time | Uses DateTime.Now and FileInfo.CreationTime (local) | FileInfo.CreationTime is local system time; using DateTime.Now compares local times. Deletion logic depends on server local clock. Consider using CreationTimeUtc and DateTime.UtcNow. | | testdata/Program.cs | DB backup filename uses current time | Create backup filename | Uses DateTime.Now formatted | This is fine for local dev; non-critical. Using UTC recommended for consistency. | | Services/ExpenseClaimService.cs | Many places: sample data uses DateTime.Now.AddDays(...), SubmittedDate = DateTime.Now, ClaimDate = DateTime.Today, AddExpenseClaim uses SubmittedDate = DateTime.Now, MarkReceiptViewed uses passed viewedAt (controllers pass DateTime.UtcNow mostly) | Setting/initializing claim and line dates and submission times | Mix of DateTime.Now, DateTime.Today, and DateTime.UtcNow | Inconsistent: some places use UTC for nudges/seen/LastNudgedDate (DateTime.UtcNow) and seen inserts; other places (e.g., sample data, AddExpenseClaim/SubmittedDate, pay/reject flow) use DateTime.Now (server local). ClaimDate and LineDate are date-only semantics (use DateTime.Today) — consider storing as DateOnly or normalizing. | | Pages/ExpenseClaims/Details.cshtml | Display/logic for nudging: uses (DateTime.UtcNow - Claim.SubmittedDate).TotalDays | Compute deltas for business logic | Uses DateTime.UtcNow compared to Claim.SubmittedDate | If SubmittedDate was stored using DateTime.Now (local), the subtraction may produce incorrect durations. Ensure stored kind matches comparisons (prefer UTC storage). | | Pages/Shared/_Layout.cshtml | Footer uses @DateTime.Now.Year | Show current year | DateTime.Now (local) | Only for display. Acceptable, but if server local differs from user's, year still correct in almost all cases. | | Pages/ExpenseClaims/PaidIndex.cshtml.cs | Return CSV/XLS filenames with timestamp using DateTime.Now | File download name | DateTime.Now | Filename timestamp uses server local time. Not critical but inconsistent. Consider UtcNow for uniqueness and sorting. | | Pages/SysAdmin/EditExpenseClaim.cshtml | Parse posted form date fields using DateTime.TryParse(Request.Form["SubmittedDate"]) | Accept date/time inputs from admin UI | Uses DateTime.TryParse (Unspecified Kind) | No culture or kind specified; results may depend on server culture. Better to parse with invariant culture or use explicit formats or use client-side ISO 8601 with timezone. | | Pages/Account/Auth0Callback.cshtml.cs and FakeLogin/Onboarding | Set Expires / ExpiresUtc using DateTimeOffset.UtcNow or DateTimeOffset.UtcNow.AddDays | Session/expiry times | Uses DateTimeOffset.UtcNow | Good practice — expiry stored as offset. | | Pages/ExpenseClaims/ReceiptController.cs & Pages/SysAdmin/SetReceiptRead.cshtml.cs | Call MarkReceiptViewed(..., DateTime.UtcNow) | Mark receipt viewed time | Uses DateTime.UtcNow | MarkViewed stored as provided DateTime. Ensure model types are DateTime with Kind=UTC or DateTimeOffset. | | Pages/ExpenseClaims/OverseerView.cshtml | Compare DateTime.UtcNow - claim.LastNudgedDate | UI business logic | Uses DateTime.UtcNow | Good where LastNudgedDate is stored as UTC. | | Pages/Company/Reports.cshtml.cs | Report ranges: DateTime.Now.AddDays(-7), etc. | Build report start date | Uses DateTime.Now | Using Now could cross-day boundaries compared to UTC. If reports expected to be local to company, convert appropriately. | | Various Model properties (AppUser.CreatedAt, ExpenseClaim.SubmittedDate, ActionLog.DateTime, AuditLog.DateTime, ExpenseLine.LineDate, etc.) | Model field declarations | Data storage types | Mixed — some initialized with UtcNow, others not | Consider migrating all timestamp fields to DateTimeOffset and ensure values are stored consistently as UTC offsets. |

Notable files & excerpts

  • Services/ActionLogService.cs: uses DateTime.UtcNow when inserting ActionLog/AuditLog entries.
  • Pages/Shared/_AuditLogPartial.cshtml: displays logs with @log.DateTime.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss") — this converts server UTC to server local timezone.
  • Services/TemporaryFileCleanupService.cs: uses DateTime.Now and FileInfo.CreationTime (local) when checking for old files.
  • Services/ExpenseClaimService.cs: mixed uses — DateTime.UtcNow for nudges and SeenDate inserts, but DateTime.Now used in Add/Update/seed/sample data.
  • ObjectEditor.cs: several DateTime.TryParse calls when importing/updating data; no explicit culture or kind.

Recommendations (concrete changes)

  • Migrate audit/action logs and any system events to DateTimeOffset stored in UTC (e.g., DateTimeOffset.UtcNow). This preserves timezone info.
  • Replace DateTime.Now usages used for storing events (e.g., SubmittedDate = DateTime.Now) with DateTime.UtcNow or DateTimeOffset.UtcNow.
  • For file timestamps, use FileInfo.CreationTimeUtc and compare with DateTime.UtcNow.
  • For UI display:
    • Preferred: send UTC timestamps to the browser and format/convert client-side to the user's timezone using JS Intl.DateTimeFormat or Date + toLocaleString(); or store user timezone preference server-side and format server-side using TimeZoneInfo.ConvertTimeFromUtc.
    • If converting server-side, use TimeZoneInfo and a stored per-user timezone ID instead of ToLocalTime() which uses server local timezone.
  • When parsing web form dates, prefer ISO 8601 with timezone or have client include timezone offset; parse to DateTimeOffset server-side.

Next Steps / Migration Plan

  • Inventory all model date/time fields and decide whether they should be DateTime (date-only), DateTimeOffset, or DateOnly.
  • Add a small migration to convert stored DateTime fields to UTC (if needed) and update code that writes dates to always use UtcNow.
  • Update views to consistently display times either:
    • server-side converted to user's timezone via TimeZoneInfo and a stored timezone setting, or
    • client-side conversion from UTC to local browser timezone.

If you want, I can:

  • Convert this summary into an actionable PR that updates the most important code sites (TemporaryFileCleanupService, ExpenseClaimService Save/Update points, ObjectEditor parsing) to use UTC and DateTimeOffset where appropriate.
  • Add a README or migration script showing how to migrate existing DB dates.