Platform management reference. Read end-to-end once, then use as a lookup.
New customers sign up themselves at the signup page. Every signup gets a free 30-day trial (extendable by one more month upon request) β no manual approval needed.
The signup page is at /signup. The new owner fills in:
After signup, the owner is signed in automatically and lands on the onboarding page. The company gets status: trial with a 30-day countdown. If the client requests more time, the superadmin can extend the trial by another 30 days from the Admin dashboard. When the trial expires, API access is blocked until you activate them.
/superadmin) to monitor signups, trial expiry dates, and activate companies for paid plans.One company = one isolated world. A dispatcher in Company A cannot see orders, drivers, stores, or anything else from Company B. This is enforced at the database layer.
Every row in orders, drivers, stores, audit_events, customers has a company_id foreign key. A SQLAlchemy before_flush guard in database.py (_tenant_guard) refuses any write that doesn't match the session user's company_id. There is no escape hatch in the API layer.
What this means practically:
psql on the server) bypass this guard. Use with care.company_id = Column(Integer, ForeignKey('companies.id'), index=True) β the guard picks it up automatically. No extra code needed.Owners invite team members from the Team page. Each invite generates a one-time link.
On the Team page (/users-page):
dispatcher, accountant, or driver.Valid roles: owner, dispatcher, accountant, driver. See section 11 for what each can do.
A "store" in Tariq is a depot β the starting point for route optimization. Every company has at least one.
Each driver gets a unique URL that they open in their phone browser. No app install, no password. If that URL leaks, you rotate it.
Adding a driver on the Drivers page: name + phone + vehicle + commission per stop (IQD). On save, the server generates a URL like /driver?t=abc123.... Send it to the driver via WhatsApp.
Rotating the token when a phone is stolen, a driver leaves, or the URL was shared outside your team:
New URL β will only be shown once. Copy it now:
The rotation modal. Close is disabled until you check the acknowledgement.
token_rotated: true indicator for drivers whose legacy URL has been revoked. Use that to spot stale driver records.WhatsApp notifications are owner-only and opt-in. The Settings page has one toggle + three template textareas.
Provider chip tells you the current state:
Three templates, each supports variables:
order_created β sent when a new order lands.out_for_delivery β sent when the dispatcher clicks "Notify customers" after route generation.delivered_with_links β sent automatically when an order transitions pending β delivered. Includes tracking + rating links.Variables available: {customer}, {order_id}, {driver_name}, {track_url}, {rate_url}. Leave a template blank to use the built-in default.
Every mutation in Tariq β every order created, every status change, every token rotation, every login attempt β is written to the audit log. This is your forensic trail.
Common actions to look for:
auth.login.failed β failed password attempt. Many of these = brute force.order.create / order.update / order.delete β CRUD on orders.order.status_change β pending β delivered / failed transitions.order.reconcile β cash handover from driver to dispatcher.driver.token.rotated β security event; investigate if you didn't do it.notify.sent / notify.failed β WhatsApp send attempts; phone redacted to last 4 digits.Red banner at top of the audit page = rate alarm. Shows when auth.login.failed > 10 per hour. Click into the filter to investigate.
Export CSV button: date range β downloads tenant-scoped audit rows. Open in Excel, share with compliance, archive off-server.
companies.plan.audit_retention_days if a tenant has longer compliance requirements.Same /report page the dispatcher uses, but viewed through a platform-owner lens.
What to scan for, in order:
First-time setup. One-time cost in your time, then it just runs.
Account SIDAuth TokenWhatsApp sandbox number (e.g. +14155238886)github.com/Ahmedabdulla80/tariq β Settings β Secrets and variables β Actions:
TARIQ_TWILIO_ACCOUNT_SIDTARIQ_TWILIO_AUTH_TOKENTARIQ_TWILIO_WHATSAPP_FROM (format: +14155238886, no whatsapp: prefix)TARIQ_NOTIFY_PROVIDER=twilio, TARIQ_NOTIFY_BASE_URL=https://tariq.codeator.ai, TARIQ_NOTIFY_DEFAULT_CC=+964.main, or re-run the latest workflow manually. On redeploy, the provider chip on /settings-page turns green.What to do when something bad happens.
Server hardware failure / image rollback:
familycapital-sql container; it persists across Tariq container restarts. No data loss from an app restart.Postgres backup & restore:
# Backup (run on server) docker exec familycapital-sql pg_dump -U tariq tariq > tariq-$(date +%F).sql # Restore docker exec -i familycapital-sql psql -U tariq tariq < tariq-2026-04-01.sql
POD images live in a named volume pod-data, mounted at /data/pod/. To back up:
docker run --rm -v tariq_pod-data:/data -v $(pwd):/backup alpine tar czf /backup/pod-$(date +%F).tar.gz -C /data .
Stolen driver phone: rotate that driver's token (section 5). Old URL dies the instant you hit rotate. No other action needed.
Rogue dispatcher / compromised account: demote the user to accountant or delete via SQL, then review their audit log (actor_email filter) for the last 30 days to assess damage.
Orders can carry barcode identifiers. Drivers scan them with their phone camera; customers can look up orders by barcode on the public portal.
How it works end-to-end:
POST /orders/{id}/barcode.GET /orders/scan/{barcode}, which returns the order. The driver's app scrolls to that stop./customer-portal and enter the barcode string. GET /customer/status-by-barcode/{barcode} returns status without authentication.company_id.The /report page has a Predictions tab that analyzes historical data to surface patterns.
Data returned by GET /report/predictions:
The customer portal at /customer-portal lets customers check order status without contacting your team.
Two lookup methods:
GET /customer/status/{order_id} β returns order status, area, delivery time. No authentication needed.GET /customer/status-by-barcode/{barcode} β same response, useful when you print barcodes on packages.Full portal with OTP: customers can also enter their phone number, receive an OTP via WhatsApp, and see all their orders β not just one. This uses POST /customer/request-otp and POST /customer/verify-otp.
Dispatchers can manually reorder stops after the optimizer generates routes, using drag-and-drop on the Routes page.
The POST /routes/reorder endpoint accepts a driver_id and a new ordered list of order_ids. The route view page calls this when a dispatcher drags stops into a new sequence and clicks "Save Order".
Who can reorder: owners and dispatchers only. The change is reflected immediately on the driver's phone β no page refresh needed (the driver's app auto-polls).
route.reorder entry in the audit log with the driver ID and new sequence.What each role can do. β = allowed, β = blocked, π = read-only.
| Endpoint / action | Owner | Dispatcher | Accountant | Driver |
|---|---|---|---|---|
| View orders / report / audit | β | β | β | β |
| Create / update orders | β | β | π | β |
| Delete orders | β | β | β | β |
| Bulk reassign | β | β | β | β |
| Add stores / drivers | β | β | β | β |
| Delete stores / drivers | β | β | β | β |
| Rotate driver token | β | β | β | β |
| Reconcile cash | β | β | β | β |
| Notifications settings | β | β | β | β |
| Export audit CSV | β | β | β | β |
| Team management / invites | β | β | β | β |
| Reorder route stops | β | β | β | β |
| Set order barcode | β | β | β | β |
| Scan barcode lookup | β | β | β | β |
| View predictions | β | β | β | β |
| View own route + deliver/fail | β | β | β | β |
| Submit GPS location | β | β | β | β |
require_role(*roles) in main.py. Hidden β secure β the server check is the real one.