Platform & admin
Ascendly platform features for super admins (access level 5), HR, and engineering — sign-in policy, operational health, broadcast email, employee onboarding, and access-level reference.
Sign-in & domains
Google OAuth
All clients (web and desktop) use Continue with Google. After Google returns a profile, the API validates in order:
- Email domain ∈
ALLOWED_EMAIL_DOMAINS(server env) — else403 - Email verified with Google — else
403 - Employee record exists in
tbl_employees(matchgoogle_suborpersonal_data.email_address) — else403
Initial domains: outdoorequipped.com, channelprecision.com. HR must create the employee profile before first sign-in.
Work email on employee create/update
When admins create or edit an employee's work email, the API validates the address domain against the same allowlist (ensure_email_domain_allowed).
Legal pages (public)
| Route | Purpose |
|---|---|
/privacy | Privacy policy |
/terms | Terms of service |
Available without signing in. Desktop opens these in the system browser.
Session length
After Google sign-in, Ascendly issues an access token that lasts 7 days (from that sign-in, not from last activity). Closing the tab or going idle does not extend it.
| Client | Access token | Stay signed in? | When it expires |
|---|---|---|---|
| Web | 7 days | No refresh token | The signed-in app sends you back to Continue with Google, even if you are only looking at a page. |
| Desktop | 7 days, renewed in the background | Refresh token: 365 days | You stay signed in across restarts until you sign out, or until the refresh token hits one year. If renewal fails, the app asks you to sign in again. |
Using the app (heartbeats, Scorecard, Dashboard) does not reset the 7-day clock on web. Sign in again to get a new 7 days.
Operators: JWT_EXPIRE_MINUTES (default 10080 = 7 days) and JWT_DESKTOP_REFRESH_EXPIRE_DAYS (default 365). Production and staging currently use those defaults.
Desktop refresh tokens
Desktop sign-in (POST /v1/auth/google with client: "desktop") returns a refresh token in addition to the access token. The desktop app stores both in OS-encrypted storage and silently renews via POST /v1/auth/refresh. Sign-out calls POST /v1/auth/logout with the refresh token to revoke it.
Web uses the 7-day access token only (no refresh token). See Session length.
Access levels & permissions
Ascendly uses numeric access levels (1–5) on tbl_employees. Level 5 is super admin; level 1 is a standard employee.
Permissions page (/permissions)
Read-only matrix showing what each level can do across:
| Resource | Actions |
|---|---|
| Employees | view, create, request_create, approve_requests, edit, delete |
| Scorecard | view, submit, edit, delete |
| Organization | view_tree, edit_departments, assign_managers, create_cluster_or_department |
| Tasks | view, create_edit, delete |
| Configurations | view, edit |
| Dashboard | manual_sync |
| Activity logs | view |
API: GET /v1/auth/permissions (current user) · GET /v1/auth/permissions/matrix (full matrix, level 5).
Level 5 users can impersonate another employee for support — impersonation is scoped in audit logs and activity tracking.
System status (/system)
Super admins see operational health at /system.
API: GET /v1/system/status
| Check | What it reports |
|---|---|
| MongoDB | Connection ping |
| BigQuery | Configured, enabled, SELECT 1 probe |
| S3 | Configured, bucket connectivity (ATW proof images) |
| Worker | Heartbeat from tbl_worker_status (keyed by API_ENV); stale after 120s |
| BSC rolling sync | Current period, last rolling sync timestamp, interval |
Overall status is ok or degraded. Worker heartbeats are environment-scoped — local dev (API_ENV=development) and Railway staging/production each show their own worker.
Related pages: System → Notifications (/system/notifications), System → Email (/system/email), System → Teams (/system/teams), System → Visibility (/system/visibility), System → Product feedback (/system/feedback).
Product feedback
Any signed-in employee can send a bug, suggestion, or this is confusing note from the web account menu (Send feedback). Desktop does not include this form.
| Piece | Detail |
|---|---|
| API | POST /v1/feedback, POST /v1/feedback/{id}/attachments |
| Screenshots | Optional. JPEG, PNG, WebP, GIF. Up to 5 images, 5 MB each. Paste, drop, or choose files. Stored in S3 (ascendly/product-feedback/). |
| Auto-attached | Signed-in name, employee id, current page path, web vs desktop, impersonation flag |
| Admin queue | /system/feedback (level 5). Status: new → reviewing → resolved / won't fix, plus a reviewer note |
| Admin API | GET /v1/feedback/admin, PATCH /v1/feedback/admin/{id}, screenshot URLs under /attachments/{id}/url |
This is not Nella thumbs-up/down. Those rate a chat reply and stay on /system/nella.
Page visibility
Super admins control which nav areas and pages appear for everyone via System → Visibility (/system/visibility).
| API | Purpose |
|---|---|
GET /v1/visibility | Effective visibility for the signed-in client |
GET /v1/system/visibility | Full catalog + disabled keys (level 5) |
PUT /v1/system/visibility/{key} | Enable or disable a key (level 5) |
Keys are hierarchical (e.g. disabling dashboard hides all dashboard children; disabling dashboard.news.birthdays hides only the Birthdays story). Catalog includes Dashboard (News stories + five BSC pages), Scorecard tabs (including Weekly Kudos), Learning sub-pages, Organization / Schedules, and Employees.
Hidden routes redirect according to remaining visible home destinations.
Employee create requests
Level 2+ users with request_create can submit employee create requests from the Employees page (Request new employee / My requests). Approvers with approve_requests open Requests to review pending items (approve / reject) and switch to previously approved or rejected requests. Exact matrix actions: Permissions above.
Maintenance mode
Use during deploys, data cutovers, or incidents when most users should not use Ascendly while engineers verify production.
Server configuration
Set on the API service (Railway env or local .env):
| Variable | Default | Purpose |
|---|---|---|
MAINTENANCE_MODE | false | When true, API returns 503 for most routes |
MAINTENANCE_MESSAGE | (built-in default) | Optional custom text shown on the web maintenance page |
MAINTENANCE_BYPASS_EMAILS | (empty) | Comma-separated work emails that may sign in and use the app normally |
Example bypass list: admin@example.com,ops@example.com (matched case-insensitively against the employee profile email).
API behavior
| Path / caller | Behavior |
|---|---|
GET /health | Always allowed |
GET /v1/public/app-status | Always allowed — web/desktop poll this for maintenance state |
POST /v1/auth/google, POST /v1/auth/refresh | Allowed through middleware; handler rejects non-bypass emails with 503 |
| Authenticated requests | Allowed when the JWT user’s email is in MAINTENANCE_BYPASS_EMAILS |
| Everything else | 503 with { maintenance: true, message: "…" } |
The worker process is not blocked (API_ENV=worker skips maintenance middleware).
Web behavior
- Polls
GET /v1/public/app-statuson load and after sign-in. - Non-bypass users are redirected to
/maintenance(full-page message). /login,/auth/callback, and/maintenancestay reachable so bypass users can sign in.- Failed sign-in during maintenance redirects to
/maintenanceinstead of showing raw JSON.
Turn maintenance off (MAINTENANCE_MODE=false) and redeploy when verification is complete.
Admin email compose (/system/email)
Super admins (level 5) can send a broadcast message to selected employees.
| Field | Notes |
|---|---|
| Recipients | Multi-select employees (max per send); quick-add by org group |
| Subject | Required |
| Body | Rich text (plain + HTML) |
| Action URL | Optional deep link in email / in-app |
| Delivery | Email (Gmail delegation), In-app notification, or both |
API: POST /v1/system/email/send
Requires Gmail delegation configured on the API (NOTIFICATION_EMAIL_* env vars). Per-recipient results show email and in-app delivery status. Actions are audit-logged.
Use for company announcements — not for automated scorecard notifications (those use the notification type catalog).
Teams channel (/system/teams)
Super admins (level 5) connect one Teams channel and post operational notices there. Recipients are everyone in that channel, not a picked employee list — that is why this is separate from email compose.
| Field | Notes |
|---|---|
| Webhook URL | Teams Workflows “Post to a channel when a webhook request is received.” Secret; shown masked after save |
| Automated posts | Master switch for lock / missing-eval notices. Off by default. Test and compose still work |
| Test | Sends a sample Adaptive Card |
| Compose | Subject + plain body + optional Open in Ascendly link; footer “Posted by {admin}” |
| History | Recent posts with success/error |
Allowlisted catalog types (lock approaching, missing evals) post once per event only when this switch is on and Also post to the Teams channel is on for that type. Missing-evals cards use department counts only.
API: GET/PUT/PATCH/DELETE /v1/system/teams/connection, POST /v1/system/teams/test, POST /v1/system/teams/compose, GET /v1/system/teams/posts
Optional env: TEAMS_WEBHOOK_URL (overrides the URL saved in the app).
Welcome email (Employees)
On Employees (/employees), admins with create/edit access can select one or more rows and Send Welcome Email.
API: POST /v1/employees/welcome-email with { employee_ids: string[] }
Sends a branded welcome message (email when configured) and can emit an in-app notification. Useful after HR creates a profile so the employee knows they can sign in with Google.
Activity tracking
Ascendly records sign-in time, last active (web) and last active (desktop), and active minutes per client. Managers see split columns on Employees; employees see their own summary on Profile (web) or Home (desktop).
Full rules — visibility, heartbeats, throttling, impersonation, and HR troubleshooting: User activity.
API: GET /v1/employees/activity-export for team CSV export (same scope as the employee list).
Related docs
- Notifications — in-app + email delivery, type catalog
- User activity — last active, active minutes, heartbeat rules
- Desktop app — tray, offline banner, 365-day refresh tokens
- API reference — route index
- BigQuery dashboard — sync jobs, worker
- What's in Ascendly — product map
- News — BSC Passers, birthdays
- Learning — modules and authoring
