taskori-admin est le back-office interne de Taskori. C'est une application PHP 8.1 / Apache tournant dans Docker, exposée sur admin.taskori.app derrière Traefik. Elle centralise la supervision des entreprises clientes, la gestion des abonnements Stripe, les backups multi-bases, les logs applicatifs, la sécurité et le support via Chatwoot.
gitlab.lorva.dev/taskori/taskori-adminhttps://admin.taskori.apptaskori-admintaskori-admin/
├── index.php # Routeur principal (pages + API)
├── config/
│ ├── config.php # Inclusion de conf.php généré
│ └── conf.php.tpl # Template → conf.php via envsubst au démarrage
├── lib/
│ ├── admin_auth.php # Auth session + auto-ban IP
│ ├── admin_db.php # Connexions PDO (admin / auth RO+RW / share)
│ ├── stripe_helper.php # SDK Stripe (checkout, portal, prices, invoices)
│ ├── chatwoot.php # Client cURL Chatwoot
│ ├── share.php # Upload/liens fichiers via API interne share
│ ├── mail_functions.php # Envoi email via PHPMailer + template HTML
│ ├── backup_helpers.php # Fingerprint, rotation, rmdir_recursive
│ ├── run_backup.php # CLI runner de backup (spawné en async)
│ └── sidebar.php / head.php / foot.php / i18n.php / docker.php
├── pages/
│ ├── dashboard.php
│ ├── companies.php
│ ├── company.php
│ ├── backup.php
│ ├── logs.php
│ ├── payments.php
│ ├── invoices.php
│ ├── support.php
│ ├── security.php
│ ├── settings.php
│ └── login.php
├── api/
│ ├── companies.php # Actions AJAX entreprises (suspend, plan change)
│ ├── backup.php # Déclenchement / status backup via Redis
│ ├── stripe.php # Actions Stripe admin + API interne (checkout, portal)
│ ├── webhook.php # Réception webhooks Stripe
│ └── chatwoot.php # Proxy AJAX conversations
├── docker/
│ └── supervisord.conf # Apache + Supervisor
├── Dockerfile
├── docker-compose.yml
└── .gitlab-ci.yml
| Page | Route | Description |
|---|---|---|
| Dashboard | /dashboard |
KPIs globaux : entreprises, utilisateurs, storage, backups, erreurs 24h |
| Companies | /companies |
Liste toutes les entreprises avec plan + statut |
| Company | /company?uid=… |
Détail entreprise : infos, storage, backup, abonnement Stripe, danger zone |
| Payments | /payments |
Historique paiements Stripe |
| Invoices | /invoices |
Factures par entreprise |
| Backup | /backup |
Navigation des sauvegardes par entreprise et date |
| Logs | /logs |
Visionneuse des logs Apache de toutes les apps (admin/auth/ts/project/manage/share/portal) |
| Support | /support |
Tickets Chatwoot : ouverts / en attente / résolus / tous |
| Security | /security |
IPs bloquées, historique tentatives de login |
| Settings | /settings |
Gestion admins, config trial, clés Stripe, paramètres Chatwoot |
Les endpoints API sont accessibles via /?page=api&endpoint=<nom>.
api/stripe.phpDeux modes d'authentification :
cancel_subscription, toggle_lifetime, set_trial, sync_priceX-Internal-Token: <TASKORI_ADMIN_INTERNAL_TOKEN>) : create_checkout, customer_portal, list_invoices, get_pricesLes actions internes sont appelées par taskori-manage pour initier les sessions Stripe Checkout sans exposer les clés Stripe côté client.
api/backup.phpDéclenche un backup asynchrone via proc_open + run_backup.php. Suivi du statut en temps réel via une clé Redis backup:job:<company_uid> (TTL 1h).
api/companies.phpActions AJAX sur les entreprises : suspension/réactivation de compte, changement de plan.
api/webhook.phpRéception des webhooks Stripe (signature HMAC). Met à jour le statut d'abonnement en base auth.
api/chatwoot.phpProxy AJAX pour les conversations Chatwoot. Utilisé par la sidebar pour le badge en temps réel (polling 60s).
admin_users (username + bcrypt hash)session.save_handler = redis)$_SESSION['admin_ip']) pour empêcher le vol de sessionip-api.com pour les bansQuatre connexions PDO configurées dans lib/admin_db.php :
| Fonction | Base | Accès | Usage |
|---|---|---|---|
get_admin_pdo() |
taskori_admin (DB_NAME) |
RW | Tables internes admin (admin_users, login_attempts, blocked_ips, stripe_prices, stripe_settings) |
get_auth_pdo() |
taskori_auth |
RO (AUTH_DB_USER) | Lecture companies, users, user_company_roles |
get_auth_write_pdo() |
taskori_auth |
RW (AUTH_DB_WRITE_USER) | Suspension, changement de plan, Stripe customer_id |
get_share_pdo() |
taskori_share |
RO | Stats de stockage (table buckets) |
AUTH_DB_WRITE_USER dispose des ALL PRIVILEGES sur toutes les bases taskori_* côté serveur DB.
L'admin lit directement la table buckets de taskori_share via get_share_pdo().
SUM(storage_used) + comptage des buckets à >=80% de quotastorage_used du bucket de l'entreprise, avec barre de progression colorée (vert / orange / rouge selon le % d'utilisation vs quota du plan)
lib/share.php expose deux fonctions utilisées par le module support :
share_upload_ticket_file() : POST vers TASKORI_SHARE_INTERNAL_URL/api/internal/upload.php avec header X-Taskori-Share-Tokenshare_create_ticket_link() : crée un lien de partage public 30 joursUn backup par entreprise est lancé manuellement (bouton UI) ou automatiquement (cron externe). Le processus principal appelle api/backup.php?action=start, qui fork un sous-processus php lib/run_backup.php <uid> <redis_host> <redis_port> <company_name> <force>.
Pour chaque entreprise, les éléments suivants sont dumpés par mysqldump :
| Clé | Base | Contenu |
|---|---|---|
auth.sql.gz |
taskori_auth |
Tables de l'entreprise (company, users, roles, tokens…) |
project.sql.gz |
taskori_project |
Projets, tâches, clients de l'entreprise |
ts.sql.gz |
taskori_ts |
Entrées timesheet |
manage.sql.gz |
taskori_manage |
Données manage |
share.sql.gz |
taskori_share |
Bucket + métadonnées fichiers |
files.tar.gz |
NFS | Fichiers physiques dans SHARE_NFS_PATH/<uid>/ |
/opt/taskori-admin/backups/
└── <company_uid>/
└── <YYYY-MM-DD>/
└── <HH-MM>/
├── auth.sql.gz
├── project.sql.gz
├── ts.sql.gz
├── manage.sql.gz
├── share.sql.gz
├── files.tar.gz
└── .fingerprint
Support du format legacy (fichiers directement dans <YYYY-MM-DD>/ sans sous-dossier heure).
skipped (pas d'écriture disque inutile).rotate_with_monthly()).Le statut est stocké dans Redis avec TTL 1h. Statuts possibles : pending → running → done | skipped | error.
Les clés Stripe (STRIPE_SECRET_KEY, STRIPE_PUBLISHABLE_KEY, STRIPE_WEBHOOK_SECRET) sont injectées via variables d'environnement et/ou stockées dans la table stripe_settings de taskori_admin.
TRIAL_DAYS). Appelé par taskori-manage via l'API interne.stripe_prices (plan + currency + interval + stripe_price_id). Les prix Stripe sont immuables, chaque modification crée un nouveau Price object.Configuration via variables CI/CD ou interface Settings : CHATWOOT_URL, CHATWOOT_API_TOKEN, CHATWOOT_ACCOUNT_ID, CHATWOOT_INBOX_ID.
lib/share.php → lien public 30j injecté dans la réponseLa page /logs lit les fichiers Apache des 7 services montés en volumes read-only dans le conteneur :
| App | Chemin dans le conteneur |
|---|---|
| Admin | /var/log/apache2/ |
| Auth | /var/log/taskori-auth/ |
| Timesheet | /var/log/taskori-ts/ |
| Project | /var/log/taskori-project/ |
| Manage | /var/log/taskori-manage/ |
| Share | /var/log/taskori-share/ |
| Portal | /var/log/taskori-portal/ |
Affichage des 500 dernières lignes avec colorisation syntaxique, filtrage erreurs/accès.
Pipeline GitLab en 3 stages défini dans .gitlab-ci.yml.
php -l sur tous les fichiers PHP (sauf vendor/) — tourne sur toutes les branchesdocker build + push vers le registry GitLab.env depuis les variables CI, scp vers DEPLOY_HOST:/docker/taskori-admin/, pull image + docker compose up -d| Branche | Cible | Image tag |
|---|---|---|
dev |
Runner local (docker-compose.dev.yml) |
:<branch-slug> |
main |
Production (DEPLOY_HOST) |
:<branch-slug> + :latest |
Le script de déploiement extrait toutes les variables d'environnement dont le nom commence par un des préfixes suivants et les écrit dans .env :
DB_ AUTH_ MANAGE_DB_ TS_DB_ SHARE_DB_ PROJECT_DB_
JWT_ MASTER_ APP_URL SMTP_ TASKORI_ CHATWOOT_
ENCRYPTION_ INTERNAL_ SENTRY_ SUPPORT_
Il ajoute également CI_REGISTRY_IMAGE pour que docker-compose.yml puisse référencer l'image correcte.
| Variable | Valeur par défaut | Description |
|---|---|---|
DB_HOST |
— | Hôte MySQL partagé |
DB_NAME |
— | Base taskori_admin |
DB_USER |
— | Utilisateur RW sur taskori_admin |
DB_PASS |
— | Mot de passe |
| Variable | Défaut | Base |
|---|---|---|
AUTH_DB_NAME |
taskori_auth |
Auth |
AUTH_DB_USER / AUTH_DB_PASS |
— | RO sur auth |
AUTH_DB_WRITE_USER / AUTH_DB_WRITE_PASS |
— | RW sur toutes les bases taskori_* |
TS_DB_NAME / TS_DB_USER / TS_DB_PASS |
taskori_ts |
Timesheet |
MANAGE_DB_NAME / MANAGE_DB_USER / MANAGE_DB_PASS |
taskori_manage |
Manage |
SHARE_DB_NAME / SHARE_DB_USER / SHARE_DB_PASS |
taskori_share |
Share |
| Variable | Défaut | Description |
|---|---|---|
APP_URL |
https://admin.taskori.app |
URL de base |
TASKORI_ADMIN_INTERNAL_TOKEN |
— | Obligatoire — Token pour les appels API internes (manage → admin) |
TRIAL_DAYS |
14 |
Durée de la période d'essai |
REDIS_HOST |
redis |
Hôte Redis (sessions + backup jobs) |
REDIS_PORT |
6379 |
Port Redis |
SHARE_NFS_PATH |
/mnt/NFS-data/taskori/share |
Chemin montage NFS share |
| Variable | Description |
|---|---|
STRIPE_SECRET_KEY |
Clé secrète Stripe |
STRIPE_PUBLISHABLE_KEY |
Clé publique Stripe |
STRIPE_WEBHOOK_SECRET |
Secret pour vérification des webhooks |
CHATWOOT_URL |
URL de l'instance Chatwoot |
CHATWOOT_API_TOKEN |
Token API Chatwoot |
CHATWOOT_ACCOUNT_ID |
ID du compte Chatwoot |
CHATWOOT_INBOX_ID |
ID de l'inbox Chatwoot |
TASKORI_SHARE_INTERNAL_URL |
URL interne de taskori-share |
TASKORI_SHARE_TOKEN |
Token X-Taskori-Share-Token pour l'API interne share |
SMTP_HOST / SMTP_PORT / SMTP_SECURE |
Config SMTP |
SMTP_USER / SMTP_PASS / SMTP_FROM / SMTP_FROMNAME |
Authentification SMTP |
SUPPORT_EMAIL / SUPPORT_NAME |
Expéditeur pour les emails de support |
SENTRY_DSN |
DSN Sentry (optionnel) |
Deux conteneurs dans le stack taskori-admin :
taskori-admin-web${CI_REGISTRY_IMAGE}:latest (PHP 8.1 + Apache)172.32.0.191 (réseau web) + 172.34.0.191 (réseau db)/opt/taskori-admin/logs → /var/log/apache2 (logs admin)/mnt/NFS-data/taskori/admin-backups → /opt/taskori-admin/backups (stockage backups)/mnt/NFS-data/taskori/share → /mnt/NFS-data/taskori/share (accès NFS pour backup fichiers)taskori-admin-redisredis:7-alpinetaskori-admin-network)| Package | Version | Usage |
|---|---|---|
stripe/stripe-php |
^13.0 | SDK Stripe officiel |
phpmailer/phpmailer |
^6.8 | Envoi d'emails SMTP |
firebase/php-jwt |
^6.10 | Validation JWT (tokens inter-services) |
hash_equals)taskori-manage ──(X-Internal-Token)──► api/stripe.php
└── create_checkout → Stripe API
└── customer_portal → Stripe API
└── list_invoices → Stripe API
└── get_prices → DB taskori_admin
Stripe ──(webhook)──► api/webhook.php
└── UPDATE companies SET subscription_status=... → DB taskori_auth
taskori-admin ──(X-Taskori-Share-Token)──► taskori-share API interne
└── upload fichier ticket
└── creer lien de partage 30j
taskori-admin ──(PDO RO)──► taskori_share.buckets (storage stats)
taskori-admin ──(PDO RO)──► taskori_auth.companies + users (lecture)
taskori-admin ──(PDO RW)──► taskori_auth.companies (suspend, plan, stripe_customer_id)
pages/security.php — tableau de bord 2 colonnes, tout visible sur un écran (tables à hauteur vh + scroll interne, en-têtes collants) :
taskori_auth (login_attempts, blocked_ips).taskori_admin.Chaque colonne affiche les IP bloquées (IP · pays · utilisateur · tentatives total/échecs · expiration UTC · bans · débloquer) et les tentatives récentes (date UTC · IP · pays · utilisateur · résultat), avec filtre par IP/utilisateur et filtre par résultat (Tous/Succès/Échec).
Le déblocage utilise l'action unban avec scope=admin|auth (auth → écrit taskori_auth.blocked_ips via get_auth_write_pdo).
pages/company.php : pour chaque utilisateur, ses IP de connexion (dépliables : dernière IP visible + clic pour toutes), avec bloquer / débloquer par IP. Actions block_ip / unblock_ip dans api/companies.php (écriture taskori_auth.blocked_ips). Bloquer une IP la refuse sur toutes les apps.
Les horaires de connexion et la date de création sont affichés dans le fuseau de l'entreprise (abréviation TZ) ; les autres horaires admin sont en UTC (labellisés).
lib/geo.phpDrapeau emoji + nom de pays (FR) depuis le code ISO ; geo_resolve_ips() géolocalise par lot via ip-api.com avec cache en base (taskori_auth.ip_geo).
Détails de la mécanique de blocage côté serveur : taskori-auth → Sécurité du login.