Priority was missing from the tickets list endpoint,
so colors weren't showing in the ticket table.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Priority emails are now per-customer, not per-company.
Each customer can have a list of email addresses that
automatically elevate ticket priority to "tärkeä" when
they send email. Field added to customer form under
"Lisätiedot" section.
Removed separate priority_emails settings from API/rules tabs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reply form:
- Mailbox/sender selection dropdown (choose which email to reply from)
- CC field (auto-filled from incoming email CC, editable)
- Reply templates dropdown (quick insert pre-made responses)
Priority system:
- Three levels: normaali, tärkeä, urgent
- Priority dropdown in ticket detail view
- Priority-based sorting (urgent/tärkeä always on top)
- Visual indicators in ticket list (colored rows, emoji badges)
- Priority emails: per-company email list that auto-sets "tärkeä"
Response templates:
- CRUD management in Settings tab
- Dropdown selector in reply form
- Templates insert into textarea
Telegram alerts:
- Bot token + chat ID configuration in Settings
- Test button to verify connection
- Auto-alert on urgent tickets (both manual and from email fetch)
- Alert on priority email matches
Database changes:
- New tables: reply_templates, customer_priority_emails
- New columns: tickets.cc, tickets.priority
- ALTER TABLE migration in initDatabase()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
finfo_open() is not available on CloudLinux alt-php84.
Now validates by file extension first, and only uses finfo
if the extension is available. Falls back gracefully.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
With MySQL migration, data/companies/{id}/ directories may not exist.
Now creates directory automatically instead of returning 404.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
check_auth was returning branding based on active company with
wrong field name (company_nimi instead of nimi), causing Noxus Intra
to show instead of company name on refresh. Now uses dbGetBranding()
with the request domain, same as the branding endpoint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Users can only log in from domains belonging to their assigned company.
E.g. cuitunet users can only log in via intra.cuitunet.fi.
Admin users can still log in from any domain.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Allekirjoitukset tallennetaan users.json:iin (signatures-objekti, avaimena mailbox_id)
- Käyttäjälomakkeessa dynaamiset textareat jokaiselle postilaatikolle
- Allekirjoitus liitetään automaattisesti sähköpostivastauksiin (ticket_reply)
- Esikatselu näkyy tikettivastauslomakkeen alla
- Muistiinpanoihin (ticket_note) ei lisätä allekirjoitusta
- Uusi all_mailboxes endpoint palauttaa kaikki käyttäjän postilaatikot
- check_auth ja login palauttavat nyt myös user_id ja signatures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- saatavuus endpoint finds company by API key, searches only that company
- config/config_update/generate_api_key now use company config
- API tab shows active company name
- Each company has own api_key and cors_origins in their config.json
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- check_auth always reads fresh company permissions from users.json
- user_update updates session immediately when editing own permissions
- Prevents stale session showing tickets from companies user lost access to
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove temporary data_diag/data_read/data_write endpoints
- Auto-recovery now scans existing company directories if companies.json
is empty or missing (handles git deploy wiping the file)
- Auto-creates config.json for any company dir missing it
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove data/companies.json and data/companies/cuitunet/config.json from git
(tracked data files get overwritten on every deploy, causing data loss)
- Add data/companies/*/ and data/tickets.json to .gitignore
- Migration now auto-recovers companies.json and config.json if missing
(handles case where git clean removes untracked data files)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- tickets endpoint supports ?all=1 to fetch from all user's companies
- ticket_detail/reply/status/etc support ?company_id= for cross-company ops
- Support tab shows all companies' tickets with company badge on subject
- Yritykset button moved from tab bar to header (next to Käyttäjät)
- requireCompanyOrParam() helper for ticket endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous check (directory existence) failed on production because
git pull created data/companies/ from committed config.json, causing
the migration to be skipped while customer data remained in data/ root.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement full multi-company architecture:
- Per-company directory structure (data/companies/{id}/)
- Automatic migration from single-tenant to multi-tenant
- Company management admin tab (create, edit, delete companies)
- Per-company IMAP mailbox configuration (multiple mailboxes per company)
- User access control per company (companies array on users)
- Company switcher in header (shown when user has access to >1 company)
- Session-based company context with check_auth fallback for old sessions
- Ticket list shows mailbox name instead of sender
- IMAP settings moved from global config to company-specific config
- All data endpoints protected with requireCompany() guard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix tickets API endpoint: add type, customer_name, customer_id, tags fields
- Add tags array to ticket data structure with add/remove UI
- Add tag filter input to toolbar and tag column in ticket list
- Add ticket_tags API endpoint for updating tags
- Add set_tags and auto_close_days actions to auto-rules
- Auto-close check runs on ticket list load, closes expired tickets
- Add tag CSS styles with editable tag badges in detail view
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Auto-rules JS: load, render, save, edit, delete, toggle rules
- Rules UI: Säännöt view with rule list and form
- Bulk actions: checkbox selection in ticket list
- Bulk close/delete endpoints (ticket_bulk_status, ticket_bulk_delete)
- Bulk toolbar with select all, close selected, delete selected
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Closed tickets completely hidden from default view, separate
"Suljetut" checkbox to toggle them with search capability
- Removed "Osoitettu" column, added "Asiakas" column to ticket list
- Customer dropdown in ticket detail view to link ticket to a customer
- ticket_customer API endpoint for linking tickets to customers
- ticket_type changelog label added
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Asiakaspalvelu tab moved to first position in navigation
- Added ticket type field (Laskutus, Tekniikka, Vika, Muu) with
type filter dropdown and type column in ticket list
- Type selector in ticket detail view with API endpoint
- Closed tickets hidden by default (selectable via "Kaikki tilat")
- Käsittelyssä rows highlighted with green background
- Type badges with color coding per category
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Production server doesn't have php-imap extension. Replaced the entire
ImapClient class to use stream_socket_client() with raw IMAP protocol
commands. Supports SSL/TLS, STARTTLS, MIME header decoding, body
extraction with encoding detection, and charset conversion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
IMAP client for fetching emails from asiakaspalvelu@cuitunet.fi,
Freshdesk-style ticket management with status tracking, message
threading, reply/note functionality, and IMAP settings in API tab.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Requires exact match of osoite + postinumero + kaupunki.
No longer exposes addresses, speeds, or any customer data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Production server (PHP 8.4) doesn't have mbstring extension,
causing 500 error on saatavuus endpoint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Public saatavuus endpoint with API key + CORS protection for
cuitunet.fi website integration. Admin settings tab for API key
management and testing. Includes standalone widget page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New Liidit tab with table, search, add/edit/delete
- Lead fields: company, contact, phone, email, address, city, status, notes
- Status workflow: Uusi → Kontaktoitu → Kiinnostunut → Odottaa toimitusta
- Color-coded status badges
- Detail view with notes display
- "Muuta asiakkaaksi" converts lead to customer with pre-filled data
- Lead CRUD endpoints in api.php with changelog logging
- leads.json added to .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- .htaccess: HTTPS enforcement, security headers, block sensitive files
- data/.htaccess: deny all direct access to data directory
- Secure session settings (httponly, secure, strict mode, samesite)
- Rate limiting on login (10 attempts per 15 min per IP)
- Math captcha on login form (server-side validated)
- Password reset via email with token (1 hour expiry)
- Forgot password UI with reset link flow
- Email field added to user management
- Updated .gitignore for reset_tokens.json and login_attempts.json
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Multi-user auth with username/password (replaces single password)
- Default admin account created automatically (admin/cuitunet2024)
- User CRUD with admin/user roles (only admin can manage users)
- All customer changes logged with timestamp, user and details
- Customer deletion now archives instead of permanently removing
- Archive view with restore and permanent delete options
- Tab navigation: Asiakkaat, Arkisto, Muutosloki, Käyttäjät
- Protect users.json, changelog.json and archive.json in .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Refactor data model: each customer now has a liittymat array (auto-migration from old format)
- Add sopimuskausi (1/12/24/36 kk) and alkupvm fields per connection
- Form supports adding/removing multiple connection rows per company
- Add "use same as installation address" checkbox for billing address
- Move stat cards to compact sidebar on the right
- Place search bar above customer table
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- File upload/download/delete per customer (max 20MB, stored in data/files/)
- Files section shown in customer detail modal
- Speed distribution chart replaces single "top speed" stat
- Bar chart shows all speeds with count, top speed bolded
- Customer delete also cleans up associated files
- data/files/ added to .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Split address into street, postal code, city (sortable)
- Add billing postal code/city fields
- Add e-invoice address and operator fields
- Add trivia stats (top postal code, top speed, avg price)
- Improved layout with stat cards grid and max-width container
- Sticky header, modal animations, search icon
- Auto-backup on every save (keeps last 30 backups)
- Footer added
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>