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>
Drops all tables (with FK checks disabled) before recreating.
Use: migrate.php?reset=1 or php migrate.php --reset
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Column name yhteyshenkilö contains ö which \w doesn't match
without the /u flag. This caused SQL syntax errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Foreign key constraints fail if charset doesn't match between
referencing and referenced tables. Added utf8mb4 to user_companies,
reset_tokens, and login_attempts tables.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PDO extension was not available on CloudLinux/alt-php84 server.
MySQLi is available, so rewrote entire database layer to use it.
Added helper functions (_dbRun, _dbFetchAll, _dbFetchOne, etc.)
that handle named parameter conversion and type binding automatically.
All public db*() function signatures remain identical.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MySQL/PDO doesn't support multiple CREATE TABLE statements in a single
exec() call. Split into an array of individual statements with a loop.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
initUsers() luo oletusadminin ennen deploy-skriptiä,
joten tiedostot eivät ole tyhjiä. Nyt ylikirjoitetaan aina.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Väliaikainen skripti joka luo companies.json, users.json, config.json
tuotantopalvelimelle. Poistettava käytön jälkeen.
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>
Dropdown siirretty header-left → header-right, kompaktimpi nappikoko
headerissa, flex-wrap tukee kapeampia näyttöjä.
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>
Default sort: status priority (käsittelyssä → uusi → odottaa → suljettu)
then by updated date within same status.
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-refresh checkbox with configurable interval (30s-5min)
- URL hash (#support, #customers etc.) persists active tab on refresh
- switchToTab() centralized function for tab switching
- Logo click uses same function
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>