376 lines
21 KiB
Markdown
376 lines
21 KiB
Markdown
# The account manager's role
|
|
|
|
The account manager has the same rights as everyone else on profiles. In addition, they have the **Manage** menu:
|
|
|
|
- **Accounts**: invite, create, edit, disable an account, reset a two-step verification, lift a block
|
|
- **Sign-ins**: the log of every sign-in attempt
|
|
- **Activity log**: the actions on all profiles
|
|
- **Retention** and **Trash**: the retention period and the deletion of profiles
|
|
- **Backup**: status, run, download
|
|
- **Errors**: unexpected errors, with their reference
|
|
|
|
They also have the CSV export of the profile list, the backup alert on their dashboard and this administration guide.
|
|
|
|
The first account created is the account manager. It can grant this role to other accounts. Keep at least two account managers: if one loses their phone and backup codes, the other resets their two-step verification.
|
|
|
|
The **Security** guide, readable by everyone, explains the protections to users. This page explains how to manage them.
|
|
|
|
# Accounts
|
|
|
|
**Manage** menu, **Accounts**.
|
|
|
|
## Inviting someone
|
|
|
|
The recommended way: nobody but the person knows their password.
|
|
|
|
1. **Invite someone** block: type their name, optional, then **Create an invitation link**.
|
|
2. Copy the link shown and send it to the person, by email or internal chat. It is shown only once.
|
|
3. The person opens the link, chooses a username and password, then sets up two-step verification. The account is active right away.
|
|
|
|
The link works once and expires after 48 hours. **Open links** lists the links not used yet. **Cancel the link** makes it unusable. Link lost or expired: create another one.
|
|
|
|
The invitation link uses the address of the page you have open. To fix it, fill in the `adresse` key of `config/config.php`.
|
|
|
|
## Creating an account
|
|
|
|
You can also create the account yourself.
|
|
|
|
1. Type the person's name.
|
|
2. Choose their username: 3 to 40 characters, unaccented letters, digits, dot, hyphen.
|
|
3. Choose a temporary password: at least 12 characters.
|
|
4. Click **Create account**, then give the username and password to the person, in person or through a different channel from the username.
|
|
|
|
At first sign-in, the person chooses their own password, then sets up two-step verification.
|
|
|
|
## Reading the account list
|
|
|
|
Each account shows its username, role, two-step verification status and last sign-in. **Two-step verification to set up** flags an account that has not done it yet. **Password to change** flags a temporary password not yet replaced.
|
|
|
|
## Editing an account
|
|
|
|
Under each account, **Change the name, username or password**. Leave the password empty to keep it.
|
|
|
|
A new password is temporary: the person changes it at next sign-in, and their open sessions close. To give one, type your own password again.
|
|
|
|
- **Disable account**: the person can no longer sign in and their sessions close at once. Their actions stay in the activity log. **Enable account** restores access.
|
|
- **Grant account management**: the account becomes an account manager. **Remove account management** does the opposite. Type your password to confirm.
|
|
- **Sign-ins** opens the sign-in log of this account.
|
|
|
|
You cannot disable your own account, nor remove your own role. An account cannot be deleted: the activity log keeps its actions.
|
|
|
|
## Forgotten password
|
|
|
|
Give a temporary password through **Change the name, username or password**. The person replaces it at sign-in.
|
|
|
|
## Lost phone
|
|
|
|
The person first signs in with a backup code, then sets up another app from **My account**.
|
|
|
|
No backup codes left:
|
|
|
|
1. Check that it really is the person: by phone, in person. A request by email is not enough.
|
|
2. Under their account, **Reset two-step verification**, then type your password.
|
|
3. The person sets up a new app at next sign-in. Their open sessions are closed.
|
|
|
|
## Blocked sign-ins
|
|
|
|
The **Blocked sign-ins** block appears while a block is active:
|
|
|
|
- a username blocked from an address, after 5 failures (15 minutes, then 30 and 60)
|
|
- an address blocked for every username, after 20 failures in an hour
|
|
|
|
**Unblock** lifts the block at once. Do it only if you know who is trying, for example a colleague who mistyped their password. A series of failures from an unknown address: leave the block and check the sign-in log.
|
|
|
|
## Requests made before version 1.8
|
|
|
|
The public account request page no longer exists. Requests still waiting show in **Account requests to approve**. **Approve** opens access: the person sets up two-step verification when signing in. **Decline** erases the request.
|
|
|
|
# Sign-in log
|
|
|
|
**Manage** menu, **Sign-ins**.
|
|
|
|
Every sign-in attempt is listed: date, account, username typed, IP address, network, browser, result. Filter by account or keep failures only. The log keeps 12 months. The scheduled task and an account manager's sign-in erase older rows.
|
|
|
|
| Result | Meaning |
|
|
|---|---|
|
|
| Signed in | Password and code correct |
|
|
| Wrong password | Known or unknown username, wrong password |
|
|
| Wrong code | Correct password, wrong two-step code |
|
|
| Attempt blocked | Attempt refused during a block |
|
|
| Account disabled | Attempt on a disabled account |
|
|
|
|
**The email alert.** When an account manager signs in from a network never seen for that account, Vivier sends an email to the `comptes.notifier` addresses, or to the sender address. The network is the address range (the first three numbers of an IPv4 address). An account's first sign-in triggers no alert.
|
|
|
|
You don't recognise a sign-in: change the account's password, reset its two-step verification, then close its sessions by disabling and enabling it.
|
|
|
|
# Errors
|
|
|
|
**Manage** menu, **Errors**.
|
|
|
|
When a page fails, the user reads "Something went wrong" and a six-character reference. The **Errors** page lists the last 300, with the reference, date, page, cause and code location. No candidate data is stored there. Pass the row to whoever maintains Vivier. **Clear the log** empties the list.
|
|
|
|
# Deleting profiles and the trash
|
|
|
|
Only the account manager deletes a profile: the **Delete profile** button at the bottom of the profile page, or **Delete** on the Retention page. Other accounts do not see these buttons.
|
|
|
|
## What deleting does
|
|
|
|
The profile goes to the trash. It disappears at once from the board, the profiles, search, client requests, follow-up, the dashboard, the CSV export and the Retention page. Its page and its documents no longer open. In the activity log, its name is replaced by its reference.
|
|
|
|
## The Trash page
|
|
|
|
**Manage** menu, **Trash**. Each line gives the profile, the deletion date, the account that deleted it and the erasure date.
|
|
|
|
- **Restore** puts the profile back, with all its data. It returns to the bottom of its column.
|
|
- **Erase now** erases the profile without waiting. This cannot be undone.
|
|
|
|
## Erasure after 30 days
|
|
|
|
After 30 days, Vivier erases the profile, the original CV, the photo, the attachments, the comments, the interviews, the follow-ups, the keywords and the history. The activity log keeps one line: the profile's reference, the account that deleted it and the date it went to the trash. No name.
|
|
|
|
Erasure happens at three moments: the scheduled task on Sunday, an account manager signing in, the Trash page being opened. A profile can therefore stay a few days longer if nobody signs in.
|
|
|
|
The period is set by `CORBEILLE_JOURS`, at the top of `src/bootstrap.php`.
|
|
|
|
## Good to know
|
|
|
|
- While a profile is in the trash, its email address stays taken. Importing the same candidate is refused: restore the profile or erase it.
|
|
- Backups already made keep the profiles deleted since. A backup made during the 30 days contains the profiles in the trash.
|
|
|
|
# Backup
|
|
|
|
**Manage** menu, **Backup**.
|
|
|
|
## What is backed up
|
|
|
|
| Item | Where | How |
|
|
|---|---|---|
|
|
| Database | Email and copy on the server | Every week, by the scheduled task |
|
|
| Files: CVs, reports, attachments, photos | Download | By hand, **Download the files archive** button, after typing your password |
|
|
|
|
The database holds the profiles, comments, interviews, follow-ups, requests, activity log and accounts. The files are too heavy for an email.
|
|
|
|
## The weekly backup
|
|
|
|
The hosting's scheduled task runs the `cron/sauvegarde.php` script. The script:
|
|
|
|
1. exports the whole database to an SQL file
|
|
2. compresses it into a zip
|
|
3. keeps a copy in `stockage/sauvegardes/`
|
|
4. sends the zip to the addresses set in `config/config.php`
|
|
|
|
The file is not encrypted. It holds candidates' data, password fingerprints and the encrypted two-step verification keys. Its protection is that of the inboxes that receive it: strong password and two-factor authentication.
|
|
|
|
## Scheduling the task at OVH
|
|
|
|
1. Control panel, hosting, **More** tab, **Scheduled tasks**, **Add a schedule**.
|
|
2. Command: `vivier/cron/sauvegarde.php`. Language: PHP 8.3.
|
|
3. Frequency: the day and hour you want. OVH does not set minutes: a task planned for 6 am starts between 6:00 and 6:59.
|
|
4. Report address: optional. OVH sends what the script prints to it.
|
|
|
|
## Checking that it works
|
|
|
|
1. Backup page, **Send a test email, without attachment**. Check the inboxes, spam folders included.
|
|
2. Tick **Also send the backup by email**, then **Back up now**.
|
|
3. Open the zip you receive: it contains a `.sql` file.
|
|
4. After the scheduled task has run once, check the "Scheduled task" line in the history.
|
|
|
|
If the email lands in spam, create a rule for the sender. The domain of the sender address must authorise the OVH server in its SPF record, and publish a single SPF record.
|
|
|
|
## Alerts
|
|
|
|
| Signal | Meaning |
|
|
|---|---|
|
|
| "ÉCHEC de la sauvegarde" email | The backup failed, or it was made but could not be sent. The email is written in French |
|
|
| Red banner on the dashboard | No successful backup for more than 8 days, or a problem with the last one |
|
|
|
|
The banner covers the case where the task no longer starts or the email no longer goes out: in that case no alert email arrives.
|
|
|
|
## Copies on the server
|
|
|
|
The history on the page lists every backup. **Download** fetches the zip. **Delete** removes the copy from the server, not the emails received.
|
|
|
|
The `semaines_conservees` setting sets how long: 0 keeps every copy, a number deletes older copies.
|
|
|
|
A copy still holds profiles deleted since. To respect the data retention period, delete old backup copies and emails.
|
|
|
|
## If the file gets too heavy
|
|
|
|
Above `taille_max_email`, Vivier runs the export again without the search index, which can be rebuilt. If it is still too heavy, the email goes out without attachment and the file is downloaded from Vivier.
|
|
|
|
## Restoring
|
|
|
|
1. phpMyAdmin, Vivier's database, **Import** tab: load the `.sql` file from the zip. It replaces every table.
|
|
2. By FTP, copy the `docs/` and `photos/` folders from the files archive into `stockage/`.
|
|
3. If the SQL file says at the top that the search index is not included: Manage menu, Accounts, **Reindex all profiles**.
|
|
4. Keep `config/cle-secrets.php`, or the `cle_secrets` key: it decrypts the two-step verification keys in the backup.
|
|
5. Sign in. Accounts, passwords and two-step verification are those of the day of the backup.
|
|
|
|
Download the files archive on the same day as the database backup: the database only finds the files that existed that day.
|
|
|
|
# Installing on OVH hosting
|
|
|
|
Vivier needs PHP 8.3 and a MySQL or MariaDB database. No framework, no dependency to install.
|
|
|
|
1. Control panel, **Databases** tab: create a MySQL database. Note the host, name, user and password.
|
|
2. phpMyAdmin, **Import** tab: load `sql/schema.sql`.
|
|
3. Upload the whole `vivier/` folder by FTP, next to `www/`.
|
|
4. **Multisite** tab: add the subdomain with `vivier/public` as root folder. Tick SSL.
|
|
5. Copy `config/config.exemple.php` to `config/config.php` and fill in the database.
|
|
6. Open the site address with `https://`. The first-run page creates your account, the account manager, then has you set up two-step verification.
|
|
7. Schedule the weekly backup.
|
|
|
|
The root folder must be `vivier/public`. The other folders then cannot be reached by an address. `.htaccess` files block them too, as a second protection.
|
|
|
|
| Folder | Purpose |
|
|
|---|---|
|
|
| `public/` | Web root: `index.php`, styles, scripts, fonts |
|
|
| `src/` | PHP code |
|
|
| `vues/` | Screens |
|
|
| `lang/` | Translations of the interface and the CVs |
|
|
| `aide/` | The texts of this help |
|
|
| `config/` | Configuration |
|
|
| `stockage/` | CVs, documents, photos, backups |
|
|
| `cron/` | Weekly backup script |
|
|
| `sql/` | Database creation and migrations |
|
|
| `claude/` | Instructions, schema and example for the Claude analysis project |
|
|
| `tests/` | Tests |
|
|
|
|
# Updating
|
|
|
|
1. Export the database in phpMyAdmin, **Export** tab.
|
|
2. Run, in order, the `sql/migration-*.sql` files that have not been run yet.
|
|
Migration 1.5 adds the trash and account requests. It also creates the account manager `ypilla`, or updates its password and role if it exists.
|
|
Migration 1.8 adds two-step verification, invitations, the sign-in log, nationality, work permit, classified availability and the Europass CV fields. It classifies the availability already entered and keeps the original text as a note.
|
|
3. Replace by FTP the `public/`, `src/`, `vues/`, `lang/`, `aide/`, `cron/`, `sql/`, `claude/` and `tests/` folders. Keep `config/config.php` and `stockage/`.
|
|
4. Copy the new keys of `config/config.exemple.php` into `config/config.php`. In 1.8: `adresse`, `cle_secrets`, `securite`.
|
|
5. The `config/` folder must be writable at first run: Vivier creates `cle-secrets.php` there. Otherwise, fill in `cle_secrets` yourself.
|
|
6. In Vivier: Manage menu, Accounts, **Reindex all profiles**, then **Translate all profiles**.
|
|
7. In the Claude analysis project: replace the instructions, the schema and the example with those of the `claude/` folder.
|
|
|
|
After the 1.8 update, every account sets up two-step verification at its next sign-in. Tell users: they need their phone.
|
|
|
|
# Configuration
|
|
|
|
Everything is set in `config/config.php`. This file must never be published.
|
|
|
|
| Key | Purpose |
|
|
|---|---|
|
|
| `nom_app` | The name shown in the header |
|
|
| `fuseau` | The time zone of dates |
|
|
| `db` | The host, port, name, user and password of the database |
|
|
| `societe` | IT Club's details on exported CVs |
|
|
| `claude` | The API key, the model, the maximum response length, the time limit |
|
|
| `sauvegarde` | The recipients, the sender, how long copies are kept, the maximum email size |
|
|
| `stockage` | The files folder, outside the web root |
|
|
| `taille_max` | The maximum size of an uploaded file, in bytes |
|
|
| `conservation_mois` | The retention period of a profile, in months |
|
|
| `comptes` | `notifier`: the addresses that receive the alert when an account manager signs in from a new network |
|
|
| `adresse` | Vivier's public address, used in invitation links. Optional |
|
|
| `cle_secrets` | The encryption key of two-step verification keys. Empty: Vivier creates `config/cle-secrets.php` |
|
|
| `securite` | `mots_de_passe_fuites`: `false` turns off the check for passwords found in breaches |
|
|
| `https` | `true` in production: the session cookie only travels over HTTPS |
|
|
|
|
# Automatic analysis
|
|
|
|
To turn it on, fill in `cle_api` in the `claude` key of `config/config.php`. Without a key, only the import of files already analysed is offered.
|
|
|
|
- The key is created in the Anthropic console. API usage is billed separately from a Claude subscription.
|
|
- Formats read: PDF, DOCX, ODT, MD, TXT.
|
|
- The instructions sent to Claude are those of the `claude/` folder. Changing them changes both analysis routes.
|
|
- The CV is sent to Anthropic for the analysis.
|
|
- Time limit: 240 seconds, adjustable. If the hosting cuts the request earlier, use the files already analysed.
|
|
|
|
# Profile translation
|
|
|
|
Each profile shows in the interface language. A recruiter working in English reads the titles, summary, positions and points of attention in English.
|
|
|
|
- At import, Vivier plans the profile's translation into each interface language.
|
|
- Translations run in the background, one at a time, while a Vivier page stays open for a user.
|
|
- An edited profile is queued again. Meanwhile, the original text shows with a banner.
|
|
- Comments, interview reports, client requests and work permits are not translated: they stay in their author's language.
|
|
- Names of technologies, companies, clients and projects stay as they are.
|
|
|
|
**Manage** menu, **Accounts**, **Maintenance** block:
|
|
|
|
- the number of translations to do
|
|
- the translations dropped after 3 attempts, with their cause
|
|
- **Translate all profiles** queues every profile without an up-to-date translation, and retries dropped ones
|
|
|
|
Without automatic analysis, translations go through a file, from the IT Club CV preview, as before.
|
|
|
|
# Search: index and synonyms
|
|
|
|
Vivier stores each profile in a search index. The index is updated at every import or edit.
|
|
|
|
**Reindex all profiles** (Manage menu, Accounts) rebuilds the index. Run it after a Vivier update or a restore without index.
|
|
|
|
Synonyms are set in the `synonymes_recherche` table, with phpMyAdmin:
|
|
|
|
| Type | Effect | Example |
|
|
|---|---|---|
|
|
| `seniorite` | The word becomes a seniority filter | `senior` to `confirme` and `expert` |
|
|
| `texte` | The word gains a variant | `dev` to `développeur` |
|
|
|
|
A synonym change takes effect at once, without reindexing.
|
|
|
|
# Security
|
|
|
|
The **Security** guide, in the help, describes the protections for users. Here is what falls to you.
|
|
|
|
| Setting | Value | Where |
|
|
|---|---|---|
|
|
| Two-step verification | Required for everyone, 6-digit codes (RFC 6238), 10 backup codes | `src/securite.php` |
|
|
| Password | At least 12 characters, at most 200, rejected if found in a known breach | `LONGUEUR_MOT_DE_PASSE`, `LONGUEUR_MAX_MOT_DE_PASSE` |
|
|
| Password fingerprint | Argon2id, recomputed at sign-in for older accounts | `hacher_mot_de_passe()` |
|
|
| Username block | 5 failures: 15 min, then 30 and 60 min | `ECHECS_SERIE`, `BLOCAGES_MINUTES` |
|
|
| Address block | 20 failures in an hour | `ECHECS_IP_HEURE` |
|
|
| Session | 2 h of inactivity, 12 h at most | `DUREE_INACTIVITE`, `DUREE_SESSION_MAX` |
|
|
| Invitation link | 48 h, single use | `INVITATION_HEURES` |
|
|
| Sign-in log | 12 months | `CONNEXIONS_MOIS` |
|
|
|
|
The constants sit at the top of `src/bootstrap.php` and `src/securite.php`.
|
|
|
|
Other protections:
|
|
|
|
- HTTPS required when `https` is `true`: `http://` addresses are redirected and a one-year HSTS header is sent. Set `https` to `false` only for a trial on a local machine.
|
|
- Two-step verification keys are encrypted (AES-256-GCM). The encryption key is in `config/cle-secrets.php`, created when first needed, or in the `cle_secrets` key of `config/config.php`. Back it up with `config.php`: without it, everyone has to sign in with a backup code and set up two-step verification again.
|
|
- Passwords are checked against the Pwned Passwords service: only the first 5 characters of the SHA-1 fingerprint leave the server. If the service does not answer, the password is accepted. `securite.mots_de_passe_fuites` set to `false` turns this check off.
|
|
- Your password is asked again to grant or remove account management, give a password to another account, reset a two-step verification and download the files archive.
|
|
- CSV export, activity log, retention, trash, profile deletion: account manager only.
|
|
- Site kept out of search engines: `X-Robots-Tag` header and `robots` tag on every page.
|
|
- Files stored outside the web root, under a random name.
|
|
- Every action is recorded in the activity log, with its author.
|
|
- No call to an external service, except the Claude API when automatic analysis is on, and Pwned Passwords.
|
|
|
|
# Languages
|
|
|
|
The interface exists in French and English. CVs are generated in French, English and German.
|
|
|
|
Adding an interface language:
|
|
|
|
1. Copy `lang/en.php` to `lang/xx.php` and translate the values. An untranslated key shows in French.
|
|
2. Add the language to `LANGUES_INTERFACE` in `src/i18n.php`.
|
|
3. Copy `aide/guide.en.md` and `aide/administration.en.md` with the language code, and translate them. Without these files, the help shows in French.
|
|
|
|
For a CV language, a few dozen labels are enough: see `lang/de.php`. The language is added to `LANGUES_CV`.
|
|
|
|
# Troubleshooting
|
|
|
|
| Symptom | Likely cause | What to do |
|
|
|---|---|---|
|
|
| "Configuration absente" | `config/config.php` is missing | Copy `config/config.exemple.php` and fill it in |
|
|
| "Something went wrong" | Server-side error | Manage menu, **Errors**: look up the reference the user gives you |
|
|
| A user has neither their phone nor their codes | Two-step verification lost | Check who they are, then **Reset two-step verification** |
|
|
| "Too many failed attempts" | Block after failures | Wait, or **Unblock** in Accounts if you know who is trying |
|
|
| Two-step code always rejected | Phone clock off | Set the phone's time to automatic |
|
|
| Nobody can validate their code any more | `config/cle-secrets.php` lost or changed | Put the original file back. Otherwise, everyone signs in with a backup code and sets up two-step verification again |
|
|
| "Vivier only works over HTTPS" | Form sent over `http://` | Open the address with `https://`. Check the multisite SSL certificate |
|
|
| Profiles still in French in English | Translations not done | Accounts, **Translate all profiles**, then keep a page open |
|
|
| The automatic analysis exceeds the time limit | Hosting time limit | Use the files already analysed |
|
|
| The search finds nothing | Empty index | **Reindex all profiles** |
|
|
| No backup email | Task stopped, SPF, spam folder | Test email, then check the task in the control panel |
|
|
| A file upload fails | File above 10 MB | Shrink the file, or raise `taille_max` and the PHP limit |
|
|
|
|
Tests run from the command line: `php tests/test_import.php`, then the same for `test_recherche.php`, `test_photo.php`, `test_i18n.php`, `test_suivi.php`, `test_aide.php` and `test_securite.php`.
|