Admin Guide - digitalunconciousness/shiftledger GitHub Wiki
This page covers features available only to users with the admin role.
ShiftLedger has two roles:
- Admin β full access: manage users, edit/delete any shift, access all settings, view audit log
- Regular β can log/edit/delete their own shifts, view the shared dashboard, export data
The first account created during Getting Started is always an admin.
Admins access user management from the Settings view (view 5).
- Go to Settings
- In the User Management section, fill in:
- Username β alphanumeric and underscores, 2β50 characters, must be unique
- Display Name β shown on shifts and in the UI
- Password β minimum 4 characters
- Color β optional; a color from the palette is auto-assigned if omitted
- Click Create User
New users are created as regular (non-admin) by default. To promote a user to admin, use the API:
curl -X PUT http://localhost:3000/api/users/<USER_ID> \
-H "Content-Type: application/json" \
-H "Cookie: sl_session=<YOUR_SESSION>" \
-d '{"is_admin": true}'If you want users to create their own accounts, they can use POST /api/auth/signup without admin involvement. This is primarily used by the mobile app. The first signup is granted admin status; all subsequent signups are regular users.
Admins can reset any user's password without knowing the current one:
curl -X POST http://localhost:3000/api/users/<USER_ID>/reset-password \
-H "Content-Type: application/json" \
-H "Cookie: sl_session=<YOUR_SESSION>" \
-d '{"new_password": "newpassword"}'Admins can update any user's:
- Display name
- Color
- Password
- Admin status (
is_admin: true/false)
Regular users can only update their own display name, color, and password.
Admins can delete any user except themselves (self-deletion is blocked to prevent lockout). Deleting a user:
- Removes all their active sessions (logs them out immediately)
- Permanently deletes the user record
-
Does not delete their shifts β shifts remain in the database with a
user_idreference that no longer resolves (they'll show "Unknown" in the UI)
Jobs represent roles or work locations. Any authenticated user can create jobs, and jobs are visible to household members through shared data visibility.
- In Settings β Jobs, fill in the Add Job form:
- Name β the employer/location name (required)
- Default Rate β auto-fills the hourly rate when this job is selected
- Color β used for the job indicator dot in the history table
-
Tips Paid As β how tips are received for this job:
- Cash (Nightly) β tips are given in cash at the end of each shift (default)
- On Paycheck β tips are included in the paycheck
- Click Add Job
When selecting a job on the Log Shift form, the hourly rate auto-fills from the job's default rate.
Click Edit on any job in the jobs list to open the Edit Job modal. All fields are editable:
- Job Name, Default Rate, Color
- OT Threshold β weekly hours before overtime kicks in (default: 40)
- OT Multiplier β pay multiplier for overtime hours (default: 1.5Γ)
- Tips Paid As β Cash (Nightly) or On Paycheck
- Employer link (optional) β associates the job to an Employer record
- Tip calculator rounding toggle β controls whether team tip splits are rounded for that job
The Tips Paid As setting controls how the paycheck estimator treats tips for shifts logged under this job:
- Cash (Nightly) β tips are excluded from the paycheck gross (you already received them), but tip taxes are still applied since cash tips are reported income. This means your estimated paycheck will be lower because it covers taxes on money you already took home.
- On Paycheck β tips are included in the paycheck gross alongside wages.
This is configured per-job, so if you have multiple jobs with different tip policies, each is handled correctly.
Deleting a job actually archives it (sets archived = 1). Archived jobs no longer appear in the job dropdown but historical shifts retain their job association.
Employers are separate records you can link to jobs and fixed recurring income entries.
From Settings β Employers:
- Add an employer name.
- Optionally enable No Tax for tax-exempt employers.
- Save.
When No Tax is enabled, earnings tied to that employer are excluded from taxable-income calculations in the app's tax/paycheck logic.
Deleting an employer archives it and automatically clears any employer links from related jobs and fixed incomes.
Use Settings β Fixed Income to track recurring income that is not logged as shifts (for example stipends, retainers, or guaranteed monthly payments).
Each fixed income entry supports:
- Optional employer link
- Amount
- Recurrence: weekly, biweekly, semimonthly, monthly, or custom
- Optional notes
For custom recurrence, provide either an interval (in days) from an anchor date or explicit custom dates.
Archived fixed incomes are hidden from active calculations and lists.
Households allow multiple users to pool their data and see each other's shifts on a shared dashboard.
- Go to Settings β Households
- Click Create Household and enter a name
- The new household is created and you are automatically added as an admin member
- An invite code (8-character alphanumeric) is generated β share this with users who should join
Two ways to add members:
By invite code β share the code with the user; they enter it in Settings β Households β Join Household
By username invitation β send a direct invitation from the household settings:
- Open the household's member list
- Enter the target user's username and click Invite
- The user will see a pending invitation in their Settings β Households panel
- They can accept or decline
- Admin β can rename the household, invite/remove members, and delete the household
- Member β can view combined data; cannot manage the household
The household creator is automatically set as an admin. Admins can promote other members.
A household admin can remove any member from the household. The removed user's data is no longer visible to the household, but their own shifts are unaffected.
Any member can leave a household at any time. If the last admin leaves, the household is deleted automatically.
When users share a household:
- The Dashboard shows combined shifts from all members
- The History view can be filtered by individual user or shows all combined
- Jobs and templates are shared across household members
- Each user's shifts remain owned by that user β only data visibility is shared
Goals are income targets that display as progress bars on the Dashboard.
From the Dashboard, set a goal with:
-
Period β
weeklyormonthly - Target Amount β the dollar amount you're aiming for
Only one goal per period can be active at a time. Creating a new active goal for the same period automatically deactivates the previous one.
Configure your pay period type in Settings β Pay Period:
- Weekly β resets every week on your configured start day
- Biweekly β every two weeks from an anchor date
- Semimonthly β 1stβ15th and 16thβend of month
- Monthly β full calendar month
The pay week start day is also configurable (default: Monday).
Configure tax rates in Settings β Tax & Deduction Rates. Default items:
| Key | Label | Default Rate |
|---|---|---|
federal |
Federal Income Tax | 22% |
state |
State Income Tax | 5% (national avg) |
social_security |
Social Security | 6.2% |
medicare |
Medicare | 1.45% |
tip_tax |
Tip Tax (Self-Employment) | 15.3% |
You can adjust rates, add custom deductions with flat per-period amounts, enable/disable individual items, and delete items you don't need. These rates drive the Paycheck Estimate card on the Dashboard.
Note: These are rough estimates for budgeting purposes, not tax advice.
Presets are pre-calculated effective tax rate bundles based on 2026 IRS brackets and national-average state rates. They are designed for fast setup without needing to manually calculate rates.
Find them in Settings β Tax Profile Presets.
- Choose a Filing Status (Single, Head of Household, Married Filing Jointly).
- Choose your Income Range from the dropdown.
- Preview the rates shown below the dropdown.
- Click Apply Preset β this overwrites your Federal, State, Social Security, and Medicare rates in Tax & Deduction Rates. Your Tip Tax and any custom deductions are not changed.
The app automatically refreshes the baseline tax_config rates twice a year β on January 1 and July 1 β based on an internal year-indexed rate table. This keeps the defaults current without manual intervention.
The last refresh time, next scheduled refresh, and active tax year are visible in the meta line below the preset selector.
To apply the latest baseline rates immediately:
- Go to Settings β Tax Profile Presets.
- Click Refresh Baseline Now.
- Confirm the prompt β this overwrites Federal, State, Social Security, Medicare, and Tip Tax rates.
The status line below the button shows the exact time the refresh ran and when the next automatic refresh is due.
To disable automatic refreshes, set the
tax_auto_refresh_enabledkey to0in themetadatabase table.
The audit log records sensitive operations across the application. View it at Settings β Audit Log (admin only).
Logged events include:
- User logins and logouts
- Account creation (setup, register, signup)
- Password changes and admin resets
- User deletions
- Household creation and membership changes
Each entry records the actor (who performed the action), the action type, the target (affected user or resource ID), and a timestamp.
To view via API:
curl http://localhost:3000/api/audit-log \
-H "Cookie: sl_session=<YOUR_SESSION>"- Every shift is tagged with the
user_idof who created it - Regular users can only edit/delete their own shifts
- Admins can edit/delete any user's shifts
- The History view shows a colored dot next to each shift indicating which user logged it
- Dashboard and History both support a user filter dropdown to view one user's data or all combined (including household members)
- Sessions are stored server-side in the
sessionstable - Each session has a 30-day expiration
- Session tokens are signed with HMAC-SHA256 using the
SESSION_SECRET - Tokens are stored as SHA-256 hashes in the database (the raw token is never persisted)
- Deleting a user invalidates all their sessions immediately
- Logging out deletes the specific session from the database
- Mobile clients use Bearer tokens and can rotate them via
POST /api/auth/refresh