Portal authenticates, Console runs the HR business, and tenants are isolated by PostgreSQL schema.
FincoHR is not one monolith. Authentication, business logic and the operator back office are three separate Laravel applications, and the lines between them are drawn deliberately.
The only place in the system that ever checks a password. Users sign in here, choose which tenant to enter, and are handed off to Console. The marketing site you are reading also lives on Portal.
Every HR feature lives here: people, attendance, leave, payroll, performance, compliance. It has no login page and no registration page — identity can only arrive by handoff from Portal.
The service provider's own control plane: tenant provisioning, plans and cross-tenant operations. Customers never touch this application.
No shared-cookie SSO, no second login page. There is exactly one path.
The user enters their credentials at Portal. This is the only place a password is verified.
Portal writes a credential payload and issues a session_id that can be redeemed exactly once.
Console redeems the handoff for the payload and reads the user's tenant schema name from it.
Console sets the search_path for the request and creates the session. The user is inside their own company's data.
Tenant isolation is not a company_id column on every table plus the hope that every query remembers it. Each company gets its own PostgreSQL schema, and Console sets the search_path at the start of every request.
A controller does three things: validate input, resolve context, delegate. The actual rules — how annual leave accrues, whether a period may be finalized, whose rows a person may read — live in the service layer.
Thin: validate, resolve tenant context, call a service, return a consistent JSON envelope or a view.
Write rules gathered in one place instead of scattered through controllers.
Where the business logic lives: payroll calculation, leave accrual, approval workflow, compliance exports.
One class serves every tenant. Isolation comes from the per-request search_path, not from a different connection.
Tell us how you run payroll today, which time clock you use and how many departments you have. We will tell you straight whether it fits.