# Workspace Apper

## Project Identity and Boundaries

Workspace Apper is the central entry point and account-management hub for the Apper application suite.

- It brings applications together and provides navigation to the tools available to the current user and team.
- Integration management, application purchasing, and application-access management belong here.
- User profiles, account security, team settings, membership, and invitations are managed here.
- Database administration and schema ownership belong to the main **Admin Apper (`admin.apper`)** project.

Workspace is not Planner Apper. Task scheduling, Gmail inbox synchronization, CRM, invoicing, and other application-specific business workflows are not implemented as Workspace modules. Links to another Apper application do not make that application's features part of this repository.

Distinguish product responsibility from implemented behavior: this repository contains an application launcher, access records, an integration catalog, and PAYTR checkout. Do not assume a complete subscription lifecycle or automatic purchase provisioning exists without tracing the relevant code.

## Database Ownership — Mandatory

- All migrations, seeders, and schema changes are managed in `admin.apper`.
- Do not create migration files or seeders in this repository, including temporary migrations intended for later transfer.
- Never run `php artisan migrate`, `migrate:fresh`, `migrate:refresh`, `migrate:rollback`, `db:seed`, or `db:wipe` here. Do not apply schema changes through SQL or application code either.
- When a feature needs a schema change, report the required tables, columns, indexes, constraints, and compatibility requirements for implementation in Admin Apper. Do not modify the sibling project without explicit authorization.
- Shared database inspection must be read-only. Do not run ad hoc data mutations against shared or production databases.
- Existing runtime workflows do persist business records: registration, profile/team updates, access creation, and payment recording. That is distinct from database administration; do not remove these writes on the assumption that Workspace is a read-only application.
- `database/README.md` documents the shared database and points to `admin.apper/database/migrations`. Local migration, factory, and seeder directories currently have no implementation files; do not restore deleted files as routine setup.
- Connection definitions are in `config/database.php`; the default is selected by `DB_CONNECTION` with a MySQL fallback. There is no configured `mysql_remote` connection.

## Technology Stack

- PHP `^8.1`, Laravel `^10.10`.
- Laravel Jetstream `^4.3` using its Livewire stack, Fortify, and Sanctum `^3.3`.
- Livewire `^3.5`, `livewire/flux` `^1.0`, Blade, and Tailwind CSS `^3.1`.
- Vite `^5.0`, `laravel-vite-plugin` `^1.0`, Axios, PostCSS, Autoprefixer, and Tailwind forms/typography plugins.
- Guzzle `^7.8`; the current PAYTR implementation uses native cURL.
- PHPUnit `^10.1` and Laravel Pint.

Use `composer.json`, `composer.lock`, `package.json`, and `package-lock.json` as dependency sources of truth. There is no `apper/log-manager` dependency or application-owned `app/Livewire` directory in the current tree.

## Repository Map

```text
app/
├── Actions/Fortify/        Registration, profile updates, password operations
├── Actions/Jetstream/      Team lifecycle, membership, invitations, account deletion
├── Actions/Deal/           Legacy actions referencing models absent from this repository
├── Actions/Mistral/        Existing title-generation action; not routed in Workspace
├── Actions/XAi/            Existing title-generation action; not routed in Workspace
├── Http/Controllers/       IntegrationController, PayController; legacy Home/Ai controllers
├── Http/Middleware/        Locale resolution, authentication, access check, CSRF handling
├── Models/                User, Team, UserAccess, Integration, Address, Pay,
│                          Membership, TeamInvitation, ExchangeRate, ReleaseNote
├── Models/Scopes/          currentTeamScope.php, currentUserScope.php
├── Policies/              TeamPolicy
├── Providers/             Fortify/Jetstream registration and shared view data
├── Services/Payment/       PaymentGatewayInterface and PaytrService
└── Mail/                  NewUserRegistered
resources/
├── views/                 Dashboard, integrations, payment, profile, teams, auth,
│                          layouts, partials, and reusable Blade components
├── lang/                  en, tr, de, es, et, hu
├── paytr/                 Callback documentation and provider examples
├── css/app.css            Vite stylesheet entry point
└── js/app.js              Vite JavaScript entry point
routes/web.php             Workspace pages, locale switching, checkout, callback
routes/api.php             Sanctum-protected GET /api/user
tests/                     Jetstream/Fortify feature tests and basic unit test
```

## Main Workflows

### Application Launcher and Access

- `/dashboard` renders `resources/views/dashboard.blade.php` directly from a route closure.
- `ViewServiceProvider` registers a global view composer supplying Workspace branding, application access, integration flags, localized tool names, exchange rates, and recent release notes.
- `User::userAccesses()` relates the user to `user_accesses`; records include `user_id`, `current_team_id`, `type`, `access_level`, and `service_id`.
- Dashboard tool links use `https://{type}.apper.com.tr/dashboard`. Poscloud and Sabeeapp have separate external links. Treat these as cross-application navigation, not proof of a locally implemented SSO protocol.
- Workspace admin visibility is derived from an access record with `type = workspace` and `access_level = admin`. UI visibility is not a substitute for server-side authorization.
- The global composer queries exchange rates and release notes even for guest views. Page rendering can therefore require a working database; do not assume the welcome or registration page is database-independent.

### Registration, Users, and Teams

- `CreateNewUser` validates registration and uses a transaction to create the user, personal team, current-team assignment, and default application access. It also sends `NewUserRegistered` mail.
- Family/default accounts receive `budget`, `planner`, and `note`; business accounts receive `sale`, `finance`, `planner`, and `note`. A checked `posmanager` option adds that tool. Default registration does not create a `workspace` access record.
- Fortify actions handle profile information, saved interface language, and passwords. Jetstream actions and `TeamPolicy` handle team creation, updates, membership, invitations, and deletion.
- `Team` stores type, currency, and timezone. `UpdateTeamName` currently updates name and timezone; do not assume all model fields are editable through that action.
- Jetstream teams/invitations and account deletion are enabled. Its API UI, profile-photo feature, and terms/privacy feature are currently commented out in `config/jetstream.php`.
- Fortify registration, password reset, profile/password updates, and confirmed two-factor authentication are enabled. Email verification is currently commented out, and `User` does not implement `MustVerifyEmail`, despite the `verified` middleware appearing on Workspace routes.

### Integration Catalog

- `IntegrationController::index()` combines current-team integration records, catalog definitions, and the team's official address.
- Catalog definitions currently live in `getIntegrationDefinitions()`: `gib`, `pos`, `sabee`, `inpos`, `getir`, and `yemeksepeti`. Prices and package metadata are defined there; verify them instead of duplicating them elsewhere.
- UI entry points are `resources/views/integrations/index.blade.php`, `resources/views/components/integration-modal.blade.php`, and slug-specific partials under `resources/views/integrations/modals/`.
- Paid modal forms submit to `pay.initiate`; JavaScript redirects to the returned PAYTR iframe URL. The current controller reads the stored official address, not the modal's submitted address fields.
- Only the integration index route is registered locally. A catalog item or start button does not prove that connection, credential saving, or activation is implemented.
- GİB uses `gib` in the catalog while the dashboard checks integration slug `e-files`. Verify the shared-data convention before changing either identifier.

### Payments

- `PayController` delegates to the concrete `PaytrService`, which implements `PaymentGatewayInterface`.
- Initiation validates payment amount, credit count, and package type, obtains a PAYTR token, and creates a pending `Pay` record in `pays` with user/team ownership and package metadata.
- The service converts the amount to minor units for PAYTR. Keep provider units distinct from stored monetary values.
- `POST /pay/callback` is public and specifically exempt from CSRF. It verifies the provider hash, locates the payment by `merchant_oid`, checks terminal status for duplicate delivery, and records success/failure.
- Successful callbacks return the plain `OK` acknowledgment. Preserve provider response requirements; do not wrap acknowledgments in HTML or JSON. Consult `resources/paytr/iframe-step-2.md` and compare the callback guide with actual code.
- The success/failure browser pages only display a payment belonging to the authenticated user. They must not serve as payment confirmation or grant entitlements.
- The current callback updates payment records; it does not create application access, activate integrations, or credit a balance. Treat provisioning as a separate requirement.
- The service currently has embedded merchant configuration and defaults to live mode. Never exercise real checkout during routine verification or copy credentials into documentation, logs, tests, or responses. New configuration must use environment-backed configuration without exposing secret values.

## Tenant Isolation and Authorization

- `Integration` and `UserAccess` register the team global scope. `currentUserScope` exists but is not registered by the current models; do not claim every model is automatically filtered by both scopes.
- Preserve the actual filename/class casing of `currentTeamScope` and `currentUserScope` when importing them on case-sensitive filesystems.
- `Address` and `Pay` expose a local `team()` scope, not an automatic global team filter. Apply explicit authorized user/team constraints to their queries as appropriate.
- `currentTeamScope` only filters when authenticated and accesses the user's current team. Background jobs, console execution, and public callbacks cannot rely on it for isolation.
- For tenant-owned writes, derive `current_team_id` and `user_id` from trusted context, not untrusted form values. Avoid bypassing global scopes; any necessary bypass requires explicit ownership constraints.
- `CheckUserAccess` checks access to `workspace`, not `planner`. Its alias is registered, but it is not attached to the current Workspace route group. Do not add it indiscriminately, especially because registration does not grant Workspace access explicitly.
- Use server-side validation and policies/gates for new or changed management endpoints. Team membership roles and application-access records are separate mechanisms.

## Routes and Middleware

| Route                                     | Purpose / protection                                                  |
| ----------------------------------------- | --------------------------------------------------------------------- |
| `GET /`                                   | Public welcome page                                                   |
| `GET /register`, `GET /{locale}/register` | Registration views; submission handled by Fortify                     |
| `POST /locale`                            | Language selection; updates session and authenticated user's language |
| `GET /dashboard`                          | Account center and application launcher                               |
| `GET /{locale}/{page?}`                   | Localized page handler, currently restricted to dashboard             |
| `GET /integrations/index`                 | Integration catalog                                                   |
| `POST /pay/initiate`                      | Start checkout                                                        |
| `GET /pay/success`, `GET /pay/fail`       | Payment result display                                                |
| `POST /pay/callback`                      | Public provider callback; signature validation, CSRF exception        |
| `GET /api/user`                           | Sanctum-authenticated user data                                       |

Dashboard, localized pages, integration index, and payment initiation/result routes share `auth:sanctum`, the configured Jetstream session middleware, and `verified`. Fortify/Jetstream register additional authentication, profile, and team routes; consult their feature configuration instead of assuming all routes are declared in `routes/web.php`.

## Localization and Timezone

- `config('app.supported_locales')` defines `en`, `tr`, `de`, `es`, `et`, and `hu`; default and fallback locale are `en`.
- `SetLocale` resolves user `language`, then session `locale`, then the first URL segment, falling back to `config('app.locale')` if invalid. Locale-specific route closures can subsequently set the request/session locale.
- Language selection is persisted by `POST /locale` and profile updates. Translation files are PHP arrays under `resources/lang/{locale}/`: dashboard, login, notifications, and register.
- When adding a language, update translations, configuration, and the explicit locale regexes in `routes/web.php`. Those regexes are currently hardcoded, not generated from configuration.
- Check locale-keyed tool names in `ViewServiceProvider` and day names in `resources/views/partials/navigation-bar.blade.php`; a language directory alone does not cover these arrays.
- Team timezone is stored and editable, but there is no `SetTimezone` middleware in this repository. The application timezone currently defaults to UTC.

## Development and Verification

```bash
npm run dev                              # Vite development server
npm run build                            # Production asset build
php artisan serve                        # Local Laravel server, when requested
php artisan route:list                   # Inspect registered routes
php -l app/Http/Controllers/PayController.php  # Example targeted PHP syntax check
./vendor/bin/phpunit --testsuite Unit     # Current database-independent unit test
```

- Vite inputs are `resources/css/app.css` and `resources/js/app.js`. Existing layouts also load CDN assets; inspect the relevant layout before changing JavaScript or styling dependencies.
- `app/Console/Kernel.php` has no active scheduled jobs. There are no Gmail synchronization or task-notification commands in this repository.
- Feature tests primarily cover Jetstream/Fortify plus registration access defaults. They still use `RefreshDatabase` and factories that are absent from the current working tree.
- **Do not run the full feature suite or an unqualified `php artisan test` against the current configuration.** The SQLite/in-memory overrides in `phpunit.xml` are commented out; `APP_ENV=testing` alone does not isolate the database. `RefreshDatabase` can invoke destructive migrations on the configured connection.
- Before database-backed tests, establish an explicitly isolated disposable database and an approved fixture strategy compatible with Admin Apper schema ownership. Do not recreate local migrations/factories or use the shared database merely to make tests pass.
- There is no `CreatesPlannerSchema` trait or `userWithTeam()` helper here. Report test prerequisites and coverage gaps honestly.
- Fake mail and external services in tests. PAYTR uses native cURL, so Laravel `Http::fake()` alone will not intercept its requests; mock the injected service or an appropriate transport boundary.

## Change Guidelines and Pitfalls

- Follow PSR-12, English identifiers, and concise English comments. Preserve existing conventions and avoid unrelated formatting changes.
- Prefer existing Fortify/Jetstream actions, Blade components, and payment-service boundaries over parallel implementations.
- Escape user-controlled Blade output with `{{ }}`. Preserve CSRF protection on browser forms and signature verification on provider callbacks.
- For new monetary logic, use integer minor units or precise decimal arithmetic. Validate package identity and pricing server-side; browser-provided hidden amounts are not authoritative pricing.
- Keep secrets out of code and output. Do not expose `.env`, deployment settings, integration credentials, payment tokens, or sensitive callback payloads.
- Shared user/team/access changes can affect other Apper applications. Keep shared identifiers compatible and call out cross-application impacts.
- `HomeController`, `AiController`, Deal actions, and some model relationships retain references to absent business models. Verify routes and callers before using them; do not create missing Planner modules merely to satisfy legacy imports.
- Use current source/configuration as implementation evidence. The root README contains Laravel starter material; payment guides and provider examples are references, not guarantees of completed functionality.
- Keep changes scoped to the requested task, preserve pre-existing working-tree changes, and do not edit generated dependencies, compiled views, or logs.
