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
- Access your profile from the navigation menu.
- View your name, email, authentication provider, and assigned companies.
- Edit your first and last name if allowed (some external providers may restrict editing).
- Save changes to update your profile.
Linking Telegram Bot
- On your profile page copy the 5- or 6-character "Telegram code" shown.
- Open Telegram and start the Expense bot (send /start).
- When the bot prompts, paste the code you copied from your profile page.
- 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
- Access company information from the dashboard or company menu.
- View company name, users, and categories.
Managing Users and Roles
- Owners can assign roles (Approver, Payer, etc.) to users.
- Activate or deactivate users as needed.
- Use the Manage Users page to view bot link status and change roles.
- Filter and search users by name, role, or status.
Inviting New Users
- Generate an invite link from the Manage Users page.
- Copy and share the link with new users to onboard them.
- 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:
- Navigate to the Oversee page from the main menu.
- Use the filter controls (category, subcategory, status, date, user) to narrow down claims.
- Claims are shown in a responsive table (desktop) or card view (mobile).
- Click a claim to view details, including creator, category, and status.
- 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:
- Go to the Approve page.
- Filter claims by category, subcategory, or user.
- Review each claim in the table or card view.
- Click a claim to open the Approve View.
- In Approve View, review details and receipts.
- Click "Approve" to approve, or "Reject" to open a modal and enter a rejection reason.
- Actions are logged for audit purposes.
Pay Page
Purpose: Mark claims as paid, change categories, and view payment history.
How to Use:
- Open the Pay page.
- Filter and search for claims ready for payment.
- Click a claim to open the Pay View.
- Review claim details and receipts.
- Click "Mark as Paid" to record payment.
- Optionally, click "Change Category" to update claim category/subcategory.
- 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:
- Go to the To Reconcile or Reconciled page.
- Filter claims by category, subcategory, or user.
- Click a claim to open the Reconcile View.
- Review payment details and mark the claim as reconciled.
- Use audit logs to track reconciliation actions.
Submit Page
Purpose: Create and submit new expense claims.
How to Use:
- Click "Add New Claim" on the Expense Claims History page.
- Fill in claim details: date, title, category, amount, description.
- Add expense lines and upload receipts.
- Save as draft or submit for approval.
- Track status from draft to submitted.
Manage Users Page
Purpose: Assign roles, activate/deactivate users, and check bot link status.
How to Use:
- Open Manage Users from the company menu.
- View all users in a scrollable, filterable table.
- Filter by role, status, or search by name.
- Assign roles using checkboxes.
- Activate/deactivate users with the status button.
- See "Bot linked" badge for users with Telegram integration.
- Copy and share invite links for onboarding.
Profile Page
Purpose: Edit personal details, link Telegram, and view assigned companies.
How to Use:
- Access your profile from the navigation menu.
- View and edit your name (if allowed), email, and provider.
- Enter your Telegram username and follow instructions to link the bot.
- View assigned companies and bot link status.
- Save changes to update your profile.
Login/Register Pages
Purpose: Authenticate and onboard users.
How to Use:
- Go to the login page and select your login method (local or external).
- For registration, use the invite link provided by your company.
- Complete the registration form and follow prompts for external providers.
- After registration, log in and access your assigned companies.
Dashboard/Home Page
Purpose: Overview of user and company activity, quick actions.
How to Use:
- View summary cards for total claims, amounts, pending, and approved.
- Access quick links to submit claims, manage users, or view company details.
- See recent notifications and activity.
Expense Claims
Creating a New Expense Claim
- Go to the Submit page and click 'New Claim'.
- Fill in the claim details: title, amount, category, description, and claim date.
- Add expense lines for each item or receipt.
- Upload receipts and supporting documents (PDF, JPG, PNG, etc.).
- Save as draft or submit for approval.
Attaching Receipts
- In the claim form, use the upload section to attach files.
- Supported file types are listed; ensure your files meet requirements.
- Uploaded files are shown in the claim details.
Editing and Submitting Claims
- Edit any draft claim by clicking its row in the claims history.
- Update details or add/remove expense lines and receipts.
- Click 'Submit' to send the claim for approval.
Viewing Claim Status
- Track your claim's progress from draft to submitted, approved, paid, and reconciled.
- Status is shown in the claims history and on each claim's detail page.
- View rejection reasons if a claim is rejected.
Approvals Workflow
Reviewing Claims
- Approvers see claims awaiting their review on the Approve page.
- Click a claim to view its details and attached receipts.
- Use filters to narrow down claims by category, user, or date.
Approving or Rejecting
- In the Approve View, review all claim details and receipts.
- Click 'Approve' to approve the claim.
- Click 'Reject' to open a modal and enter a rejection reason.
- Submit the rejection; the claim status updates and the submitter is notified.
Notifications and Audit Logs
- All actions (approve, reject) are logged for transparency.
- Users receive notifications for approvals, rejections, and status changes via the Telegram bot when linked. Email notifications are optional and may require additional configuration.
- Approvers (and system owners) can send a "nudge" to remind approvers about pending claims — this uses the same Telegram notification path.
- Audit logs can be viewed by authorized users (Owners and Overseers) for compliance.
Payments
Marking Claims as Paid
- On the Pay page, select claims ready for payment.
- Click a claim to open its details.
- Click 'Mark as Paid' and enter payment details if required.
- The claim status updates to 'Paid'.
Changing Categories/Subcategories
- In the Pay View, click 'Change Category' to open the modal.
- Select the new category and subcategory.
- Save changes to update the claim.
Viewing Payment History
- View all paid claims on the Paid or Reconciled pages.
- Filter by date, user, or category to find specific payments.
- Payment details are shown in each claim's history.
Security and Access Control
User Roles and Permissions
- Roles include Owner, Approver, Payer, Reconciler, Submitter, Overseer, Global Approver.
- Each role grants specific permissions for claims and company management.
- Owners can assign and change roles for other users.
Company-Level Access
- Users only see claims and data for companies they are assigned to.
- Owners manage user access and roles from the Manage Users page.
- Access to claims, approvals, and payments is restricted by role and company.
Notifications and Integrations
Telegram Bot Integration
- On your profile page copy the 5- or 6-character Telegram code displayed.
- Open the Expense bot in Telegram and send /start.
- When prompted by the bot, paste the code from your profile page to link your account.
- 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
- Use the support contact provided by your company.
- Include details and screenshots if possible.
- For technical issues, provide error messages and steps to reproduce.
System Settings and Configuration
Application Settings
- Admins can manage system-wide settings from the admin panel.
- Configure company details, categories, and user roles.
- Update environment-specific settings as needed.
Audit and Activity Logs
Viewing Action Logs
- Access audit logs from the Audit page on the company dashboard.
- Filter logs by user, date, or action type to find specific events.
- Use logs to review claim actions, approvals, payments, and changes.
- In this implementation only users with the Owner or Overseer role can view audit logs.
Understanding Audit Trails
- Audit trails show who performed each action and when; audit entries are recorded when key actions occur (approvals, rejections, category changes, etc.).
- Use logs for compliance, troubleshooting, and transparency.
- 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 inWebsite.
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.NoworDateTime.Today(local machine time) — inconsistent with UTC storage. - Several places render
DateTimeto strings directly in Razor views; some explicitly callToLocalTime()while others assumeDateTimeis already local or UTC. - JSON parsing and UI form handling frequently uses
DateTime.TryParsewithout specifying culture or kind; parsed DateTime.Kind will beUnspecified. - File system timestamps use
FileInfo.CreationTimewhich returns local time; no explicit UTC calls.
- Audit/log timestamps are recorded with
Recommendations (high level)
- Standardize on storing all server-side timestamps in UTC (use
DateTime.UtcNoworDateTimeOffset.UtcNow) and persist with an explicit kind (preferDateTimeOffsetfor 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.,
LineDaterepresenting 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.ParseExactwith the expected format andDateTimeStyles.AssumeUniversal/AssumeLocalas appropriate, or parse toDateTimeOffset.
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: usesDateTime.UtcNowwhen insertingActionLog/AuditLogentries.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: usesDateTime.NowandFileInfo.CreationTime(local) when checking for old files.Services/ExpenseClaimService.cs: mixed uses —DateTime.UtcNowfor nudges andSeenDateinserts, butDateTime.Nowused in Add/Update/seed/sample data.ObjectEditor.cs: severalDateTime.TryParsecalls when importing/updating data; no explicit culture or kind.
Recommendations (concrete changes)
- Migrate audit/action logs and any system events to
DateTimeOffsetstored in UTC (e.g.,DateTimeOffset.UtcNow). This preserves timezone info. - Replace
DateTime.Nowusages used for storing events (e.g.,SubmittedDate = DateTime.Now) withDateTime.UtcNoworDateTimeOffset.UtcNow. - For file timestamps, use
FileInfo.CreationTimeUtcand compare withDateTime.UtcNow. - For UI display:
- Preferred: send UTC timestamps to the browser and format/convert client-side to the user's timezone using JS
Intl.DateTimeFormatorDate+toLocaleString(); or store user timezone preference server-side and format server-side usingTimeZoneInfo.ConvertTimeFromUtc. - If converting server-side, use
TimeZoneInfoand a stored per-user timezone ID instead ofToLocalTime()which uses server local timezone.
- Preferred: send UTC timestamps to the browser and format/convert client-side to the user's timezone using JS
- When parsing web form dates, prefer ISO 8601 with timezone or have client include timezone offset; parse to
DateTimeOffsetserver-side.
Next Steps / Migration Plan
- Inventory all model date/time fields and decide whether they should be
DateTime(date-only),DateTimeOffset, orDateOnly. - Add a small migration to convert stored
DateTimefields to UTC (if needed) and update code that writes dates to always useUtcNow. - Update views to consistently display times either:
- server-side converted to user's timezone via
TimeZoneInfoand a stored timezone setting, or - client-side conversion from UTC to local browser timezone.
- server-side converted to user's timezone via
If you want, I can:
- Convert this summary into an actionable PR that updates the most important code sites (
TemporaryFileCleanupService,ExpenseClaimServiceSave/Update points,ObjectEditorparsing) to use UTC andDateTimeOffsetwhere appropriate. - Add a README or migration script showing how to migrate existing DB dates.