# OptikRapor — Project Context
Last updated: 2026-10-19
## Purpose
Multi-tenant SaaS, hosted PHP backend on reseller hosting, dedicated PostgreSQL server, web reports and future editing screens. Initial Excel samples are from ONE TemaOptik company and branch, mostly October 2026-filtered. Eight report types: customers, detailed customers, sales, basic/detailed stocks, bestsellers, cash, expenses (empty data).
## Immutable architecture
Tenant = company, with branches. Canonical business schema must remain vendor-independent. Source systems and versioned Excel adapters introduced in migration 002. Preserve source lineage, original rows, explicit matching confidence and import auditing. Never infer ciro by summing repeated sales header columns per item.
## Current state
Repository baseline README and migrations 001/002. No production-ready parser, hosting deployment, RLS, credential system or tested imports yet. Adapter mappings are draft and require real header mapping + validation. Run migrations 001 then 002 on staging first. No production data is in repository.
## Continue new chats
Read README, this file, DECISIONS.md, IMPORT_ARCHITECTURE.md, CHANGELOG.md, migrations in order. Always add new migrations instead of editing applied scripts. Check GitHub status and previous decisions before coding. Keep code file names stable and version releases/tags separately.
## Next work
1) Validate SQL on staging PostgreSQL 14+; 2) tenant RLS, permissions and strict FK scopes; 3) map eight Excel types, create fixtures; 4) create PHP importer dry-run, idempotency tests; 5) build tenant dashboard.

## 2026-10-19 security milestone
Migration 003_security_rls.sql committed to GitHub, NOT YET run or production-tested. It introduces pgcrypto-HMAC signed short-lived context in app.auth_payload and app.auth_signature, optikrapor_private secret, tenant RLS and constrained application grants. The initial authenticated user and memberships do not exist yet. Never send secret in chats or commit it; provision to PHP protected environment separately. Branchless tables still have company-wide access for active branch members and must be refined before cross-branch rollout. Global lookup rows and login flows need deliberate read-only APIs. Rotate secret using planned secure rollover before production. Tests required: no-context deny, forged-signature deny, cross-company deny, membership disabled, branch access, SQL injection boundary.

## Deployment workflow
GitHub private db5050/OptikRapor -> local VS Code clone (git pull --ff-only origin main) -> FTP-KR to https://optikrapor.ydbteknoloji.com/app. Saving files and Git pulls may trigger different FTP-KR behaviors; verify explicit sync. Never upload entire repository or credentials to public /app. Read docs/DEPLOYMENT.md.

## PHP MVP v0.4.0
Initial hosted PHP application committed under app/; public URL /app, PostgreSQL PDO connection in app/src/Core/Database.php. Status route /app/health and optionally /app/health/database guarded by environment flag. No login or customer API yet. FTP-KR must map local app/ contents only to remote /app, not repository root. Check PHP env injection and Apache .htaccess access denial. See docs/PHP_DEPLOYMENT.md. RLS 003 execution still unconfirmed.

## PHP v0.5.0 (2026-10-19)
Protected /app/health/database endpoint added with server-side OPTIKRAPOR_HEALTH_TOKEN header check; confirms runtime PostgreSQL credentials. Not yet deployed or tested. No user login yet. Migration 003 not confirmed applied. Review docs/PHP_DEPLOYMENT.md for PowerShell test and environment requirements.

## Authentication MVP v0.6.0
Migration 004_authentication.sql and app/src/Core/Auth.php with HTML login committed; no first user provisioned yet, migrations 003/004 deployment not verified. Login uses PHP password_verify, signed session cookie, CSRF and reads active memberships. This is a development milestone ONLY: current security-definer login lookup can reveal password hashes to the app DB role, memberships are not revalidated on each request, and brute force rate limiting is missing. Do not onboard external tenants or expose sensitive APIs before hardened authentication, trusted tenant binding and security tests. See docs/AUTH_SETUP.md.

## Dashboard v0.7.0
Added a read-only modular dashboard placeholder to app/index.php and active membership refresh each authenticated request in Auth.php. No new SQL migration needed. This is NOT full role authorization: auth SQL functions, login rate limiting, CSRF/session hardening, per-branch RLS tests and reliable deployment remain to be addressed. No customer data endpoints enabled. Check hosted PHP release after BAT pull and FTP-KR sync.

## UI v0.8.0
/app/companies lists currently authorized company/branch memberships read-only; dashboard navigation added. No SQL migration required. Company/branch CRUD and user provisioning are NOT implemented yet: login_memberships(user_id) alone is not an authority proof for writes. Next step: secure signed RLS context, least-privilege tenant admin procedures, negative cross-tenant tests, then enable CRUD. Existing PHP credentials stay only in ignored app/config/db.local.php.

## Tenant management v0.9.0
Migration 005_tenant_admin.sql added (NOT confirmed executed) and PHP app/manage.php + Core/TenantDb.php. PHP uses signed short-lived RLS context from secret stored ONLY in ignored db.local.php; role-checked SECURITY DEFINER functions manage company and branches, log changes. Requires one-time secure secret retrieval from optikrapor_private.auth_signing_keys via DBeaver. See docs/MANAGEMENT_SETUP.md. Login brute-force protections, secret isolation from webroot, and full RLS negative tests are still pending; do not onboard customers yet.

## UI theme update 1.0.0
Shared CSS at app/assets/app.css. Main index.php and manage.php now use consistent responsive SaaS panel shell. GitHub committed; FTP-KR sync required. No SQL migration. Future modules MUST reuse app/assets/app.css instead of inline ad-hoc styles. Keep versioned docs in sync.

## 1.1.0 — Platform company provisioning
Run database/migrations/006_platform_company.sql as optikrapor_owner; NOT yet applied on user's DB. The privilege source is users.is_platform_admin, never client role/hidden form fields. New app/company-create.php is accessible only to signed active platform admins who possess an existing active membership as context; it provisions a new company and creator's company_admin membership transactionally. The management screen conditionally displays the link if signed database capability check succeeds. No automatic elevation of existing accounts; owner must explicitly authorize the correct account with an audited DBA operation. Never allow company_admin to provision new tenant companies.
