Commit Graph

56 Commits

Author SHA1 Message Date
14cdfafd40 feat: domain-based login restriction
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>
2026-03-10 16:36:05 +02:00
1fa366d3ff feat: add ?reset parameter to migrate.php for clean re-run
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>
2026-03-10 16:28:42 +02:00
b074b7db28 fix: add unicode flag to named param regex for ö/ä chars
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>
2026-03-10 16:26:44 +02:00
8a630508f4 fix: add DEFAULT CHARSET=utf8mb4 to all tables
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>
2026-03-10 16:24:25 +02:00
796e1b3072 feat: rewrite db.php from PDO to MySQLi
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>
2026-03-10 16:04:14 +02:00
438a9b5070 temp: phpcheck to verify PDO after Plesk change
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:57:35 +02:00
a75ba19fe5 cleanup: remove phpcheck.php diagnostic script
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:28:01 +02:00
1a18da2430 temp: add phpcheck.php to diagnose PDO availability
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:26:51 +02:00
b15efa1758 cleanup: remove setup_config.php after use
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:25:37 +02:00
42571e46f3 temp: add setup_config.php to create db_config.php on server
Will be removed immediately after use.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:24:20 +02:00
2b8e053e52 debug: add error display to migrate.php to see what fails
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:23:35 +02:00
e540ec0448 fix: split initDatabase() into separate exec() calls per table
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>
2026-03-10 15:15:55 +02:00
13e0d1255f JSON → MySQL migraatio: tietokantapohjainen datatallennus
Lisätty:
- db.php: PDO-tietokantakerros (kaikki CRUD-funktiot)
- migrate.php: JSON → MySQL migraatioskripti
- db_config.php lisätty .gitignore:en (sisältää tunnukset)

Muutettu:
- api.php: kaikki JSON load/save → db*() funktiot
- session.cookie_samesite: Strict → Lax (captcha-fix alias-domaineilla)
- Poistettu kaikki JSON-tiedosto I/O (paitsi tiedostoupload + logot)

Hyödyt:
- Git deploy ei enää ylikirjoita dataa
- Tiedostolukot ja transaktiot → ei korruptiota
- Parempi suorituskyky isoilla tietomäärillä

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:00:38 +02:00
c714f39bc5 Päivitä admin-salasana admin123 + kaikki tuotantodata
FTP:llä haettu data vanhalta intra.cuitunet.fi:
- 3 käyttäjää, admin-salasana resetoitu admin123
- 4 yritystä brändäyskentillä
- 35 CuituNet-asiakasta

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:31:46 +02:00
eed1ac5639 Migroi kaikki data vanhalta intra.cuitunet.fi -palvelimelta
FTP:llä haettu:
- 4 yritystä (CuituNet, Web1, Empor, Woima Services)
- 35 CuituNet-asiakasta + 1 liidi
- 1 Web1-asiakas
- 3 käyttäjää (admin, Jukka, ville)
- Brändäyskentät lisätty companies.json:iin

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:26:11 +02:00
52bf1bd300 Päivitä CuituNetin data vanhalta palvelimelta (intra.cuitunet.fi)
Haettu API:n kautta: 2 asiakasta, 1 liidi.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:24:44 +02:00
78af39b252 Lisää CuituNetin asiakasdata gittiin
Asiakkaat, liidit, tiketit, asetukset, arkisto ja changelog.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:19:59 +02:00
712e9a1222 Lisää data-tiedostot gittiin + dynaaminen SITE_URL
- companies.json, users.json, config.json gitin seurantaan
- SITE_URL dynaaminen HTTP_HOST:in mukaan
- MAIL_FROM vaihdettu noreply@noxus.fi
- CuituNet Intra → Noxus Intra sähköposteissa

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:18:23 +02:00
daec42600a Korjaa deploy_data.php - pakota datan ylikirjoitus
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>
2026-03-10 14:16:23 +02:00
edefd05ec6 Lisää deploy_data.php - alustaa data tuotantoon
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>
2026-03-10 14:14:07 +02:00
095dc90b6f White-label multi-domain tuki (Noxus Intra)
- CSS-muuttujat: kaikki kovakoodatut #0f3460/#16213e korvattu var(--primary-color)/var(--primary-dark)
- Uudet API-endpointit: branding (julkinen, domain-pohjainen), company_logo, company_logo_upload
- Domain-pohjainen brändäys: HTTP_HOST → yrityksen domains-arrayn matchaus
- Login: domain asettaa oletusyrityksen sessioon
- check_auth: palauttaa branding-objektin (primary_color, subtitle, logo_url)
- company_create/update: käsittelee domains, primary_color, subtitle, logo_file
- Dynaaminen login-sivu, header ja footer (logo, nimi, alaotsikko, värit)
- JS: loadBranding(), applyBranding(), yritysvaihdon brändäyspäivitys
- Admin-paneeli: brändäysasetukset (logo-upload, väri, alaotsikko, domainit)
- Git-repo siirretty intra.noxus.fi:hin

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 13:44:49 +02:00
918a5ff120 Lisää sähköpostiallekirjoitus per käyttäjä per postilaatikko
- 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>
2026-03-10 13:09:30 +02:00
11e1103eb4 Siirrä yritysvalitsin header-yläpalkkiin nappien joukkoon
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>
2026-03-10 11:46:49 +02:00
44e401f4d3 Make API key and CORS settings per-company
- 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>
2026-03-10 11:39:35 +02:00
92d52f34ad Add ticket sorting by status priority, updated, or created date
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>
2026-03-10 11:37:31 +02:00
64ff8eaa91 Fix company access: sync session from users.json on every check_auth
- 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>
2026-03-10 11:34:18 +02:00
9973485cb4 Remove temp diag endpoints, improve auto-recovery for companies.json
- 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>
2026-03-10 11:33:21 +02:00
443e8fcfc3 TEMP: Fix diag endpoint auth for production recovery
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:28:51 +02:00
6b7bdcd17d TEMP: Add data diagnostics endpoints for production recovery
Will be removed after data is restored.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:28:04 +02:00
ab03eb7e61 Fix data loss: remove data files from git, add gitignore, auto-recover
- 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>
2026-03-10 11:25:36 +02:00
9a17bc9cf5 Remove tags column from ticket list view
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:21:43 +02:00
f82f62877d Add cross-company ticket viewing and move Yritykset button to header
- 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>
2026-03-10 11:19:35 +02:00
7f89a29b94 Fix migration check: detect unmigrated data by checking data/customers.json
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>
2026-03-10 11:06:08 +02:00
c34b5a2c26 Add multi-tenant support with per-company data isolation
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>
2026-03-10 11:04:24 +02:00
562153e040 Add ticket tags system, tag filtering, and auto-close feature
- 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>
2026-03-10 10:32:09 +02:00
f918952c3f Add auto-refresh toggle and tab persistence via URL hash
- 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>
2026-03-10 10:20:24 +02:00
7fcf0a3b31 Add auto-rules management, bulk actions for tickets
- 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>
2026-03-10 10:18:10 +02:00
ea7c3e0cf7 Add closed tickets checkbox, customer linking for tickets
- 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>
2026-03-10 10:06:38 +02:00
91930c9420 Add ticket types, move Asiakaspalvelu tab first, hide closed tickets
- 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>
2026-03-10 10:01:29 +02:00
f0a7676451 Rewrite ImapClient to use raw sockets instead of php-imap extension
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>
2026-03-10 09:46:21 +02:00
42e3648e3d Add Asiakaspalvelu email ticketing system
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>
2026-03-10 08:52:00 +02:00
cc3a6c465d Add logo click to return to customers view
Clicking the CuituNet Intra brand/logo in the header
navigates back to the Asiakkaat (customers) tab.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 03:00:54 +02:00
db8b64cd5b Move user management button to header
Users button now appears next to the logged-in user info
in the top right header instead of as a tab. Only visible
to admin users.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 02:59:30 +02:00
ddc96f4164 Rename Asetukset tab to API
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 02:52:09 +02:00
37ffd7e46b Restrict saatavuus API to return only true/false
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>
2026-03-10 02:43:58 +02:00
b927cd2bf5 Fix missing mbstring: replace mb_strtolower with strtolower
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>
2026-03-10 02:39:04 +02:00
37e6f6b90e Add temporary error reporting to debug 500 on saatavuus endpoint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 02:37:16 +02:00
b8b3fb422a Fix PHP 7 compatibility: replace str_contains with strpos
str_contains() requires PHP 8.0+, causing 500 error on production.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 02:32:31 +02:00
14707b9616 Add public availability API and settings panel
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>
2026-03-10 01:50:52 +02:00
8ba925d3dc Add leads (liidit) tab for tracking potential customers
- 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>
2026-03-10 01:35:04 +02:00