# Vita Server — `https://vitatec.io/vita_server/`

Companion Laravel project that owns marketplace authority for every Vita
install. Replaces the relevant slice of `api.akaunting.com` so the Falcon
/ Vita platform can run without leaking telemetry or trust to Akaunting's
servers.

For production deployment to a shared host **without SSH access** (cPanel
/ FTP only), follow [`DEPLOY-NO-SHELL.md`](DEPLOY-NO-SHELL.md). It
explains how to upload the pre-built `vendor/` folder, import the SQL
dump at `database/dumps/vita_server_seed.sql` via phpMyAdmin, and use the
included `public/install.php` web installer to replace the `artisan`
CLI for `APP_KEY` generation and cache priming.

---

## Quick start (local)

```bash
cd vita-server
cp .env.example .env

# Adjust .env: APP_URL=http://127.0.0.1:8080, DB_DATABASE=vita_server (already exists locally)

composer install
php artisan key:generate
php artisan migrate
php artisan db:seed       # mints a dev platform token + 21 modules + 105 entitlements

php artisan serve --host=127.0.0.1 --port=8080
```

Verify with:

```bash
curl http://127.0.0.1:8080/health
# -> {"status":"ok","service":"vita-server"}
```

Then in Falcon's `.env`:

```env
VITA_MARKETPLACE_DRIVER=vita
VITA_MARKETPLACE_BASE_URL=http://127.0.0.1:8087/
```

```bash
php artisan config:clear
php artisan vita:doctor
```

---

## Production deployment — `https://vitatec.io/vita_server/`

This project is designed to be served from a **subdirectory** (`/vita_server`)
under the existing `vitatec.io` domain. Two deployment shapes work; pick
whichever your host supports.

### Option A — Subdirectory under existing docroot (recommended for shared hosting)

Upload the entire `vita-server/` folder to `htdocs/vita_server/` on the
production server. The shipped `.htaccess` files take care of routing:

```
htdocs/
├── vita/                ← Falcon
└── vita_server/         ← upload this entire folder (THIS project)
    ├── .htaccess        ← rewrites / to public/, blocks app/, config/, .env
    ├── public/
    │   ├── .htaccess    ← Laravel front controller
    │   └── index.php
    ├── app/
    ├── bootstrap/
    ├── config/
    ├── database/
    ├── routes/
    ├── storage/
    ├── vendor/          ← created by composer install on the server
    ├── .env             ← created from .env.example with production values
    └── artisan
```

On the production server:

```bash
cd htdocs/vita_server
cp .env.example .env
# Edit .env:
#   APP_ENV=production
#   APP_KEY=  (will be generated)
#   APP_DEBUG=false
#   APP_URL=https://vitatec.io/vita_server
#   DB_HOST, DB_DATABASE, DB_USERNAME, DB_PASSWORD = production MySQL creds
#   VITA_SERVER_ALLOW_DEV_TOKEN=false

composer install --no-dev --optimize-autoloader
php artisan key:generate
php artisan config:cache
php artisan route:cache
php artisan migrate --force
php artisan db:seed --force      # COPY the printed token — only shown once

chmod -R 775 storage bootstrap/cache
chown -R www-data:www-data storage bootstrap/cache    # or whatever your web user is
```

Health check:

```bash
curl https://vitatec.io/vita_server/health
# -> {"status":"ok","service":"vita-server"}
```

The shipped root `.htaccess` does the subdirectory rewriting and blocks
direct access to `app/`, `bootstrap/`, `config/`, `database/`, `routes/`,
`storage/`, `vendor/`, `.env`, `composer.json`, etc.

### Option B — Dedicated subdomain at the same docroot (faster, more secure)

If you can point a domain or subdomain (`api.vitatec.io`, `vita.vitatec.io`,
or `vitatec.io/vita_server` via Apache `Alias`) directly at
`vita-server/public/`, that is preferred. In that case:

```apache
# Apache vhost
<VirtualHost *:443>
    ServerName api.vitatec.io
    DocumentRoot /var/www/vita-server/public
    <Directory /var/www/vita-server/public>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>
```

Or with `Alias` for keeping the existing domain:

```apache
Alias /vita_server /var/www/vita-server/public
<Directory /var/www/vita-server/public>
    AllowOverride All
    Require all granted
</Directory>
```

Either of these makes the root `vita-server/.htaccess` redundant
(it stays harmless either way).

### Wire Falcon to production

In Falcon's `.env`:

```env
VITA_MARKETPLACE_DRIVER=vita
VITA_MARKETPLACE_BASE_URI=https://vitatec.io/vita_server/
```

> **Trailing slash is required.** Guzzle's base_uri behaviour silently
> drops the last path segment if there is no trailing slash, so
> `https://vitatec.io/vita_server` (no slash) would resolve every API
> call against `https://vitatec.io/` and miss the subdirectory. The
> MarketplaceClient appends a slash defensively if missing, but write
> the value correctly to avoid surprises.

Then on Falcon:

```bash
php artisan config:clear
php artisan vita:token:set <token-from-db:seed>
php artisan vita:doctor   # expect 0 errors / 0 warnings
```

---

## Endpoint contract (v1)

The Falcon `MarketplaceClient` calls these paths. Responses follow the
shape `{ data: ... }` so the legacy `SiteApi::getResponseData` accessor
keeps working.

| Method | Path                                              | Purpose                              | Notes                                            |
| ------ | ------------------------------------------------- | ------------------------------------ | ------------------------------------------------ |
| GET    | `core/version/{core}/{php}/{mysql}/{companies}`   | Latest core version + changelog      | Falcon polls in `Versions::all()`                |
| GET    | `core/download/{version}/{php}/{mysql}`           | Stream core ZIP                      | Headers: `X-Vita-Sha256`                         |
| GET    | `apps/{alias}/version/{version}/{core}`           | Latest module version                | Falcon polls per module in `Versions::all()`     |
| GET    | `apps/{alias}/download/{version}/{core}/{token}`  | Stream module ZIP                    | Token is `vita.platform_token`                   |
| GET    | `apps/{alias}/isubscribe`                         | Is the bearer subscribed to alias?   | Returns `{data:{status,plan,grace_until,...}}`   |
| GET    | `apps/entitlements/{companyId}`                   | Full entitlements for a tenant       | Drives `vita:subscription:sync`                  |
| GET    | `modules`                                         | Marketplace catalog                  | Used by `Modules::getModules`                    |
| GET    | `modules/{alias}`                                 | Module detail                        | Used by `Modules::getModule`                     |

Other endpoints (reviews, testimonials, suggestions, vendor pages, banner
pages) return an empty `{data: []}` envelope until implemented — that
shape is exactly what every legacy caller already treats as "no data".

---

## Auth

Bearer token (Authorization header). The token corresponds to a row in
`platform_tokens` (see migration), tied to a tenant.

* In development (`VITA_SERVER_ALLOW_DEV_TOKEN=true`), any non-empty
  bearer is accepted as a synthetic dev tenant.
* In production, the bearer's SHA-256 hash must match a row in
  `platform_tokens` with `status = 'active'`.

The seeder mints a fresh token once per fresh DB and prints it to the
console. Save it the first time you see it — only the hash is stored.

---

## Files of interest

* `app/Http/Controllers/Api/V1/MarketplaceController.php` — all 8 endpoints.
* `routes/api.php` — registered under `/`.
* `database/migrations/*` — `platform_tokens`, `modules`, `module_versions`,
  `entitlements`.
* `database/seeders/DatabaseSeeder.php` — idempotent seed: mints a token,
  21 modules + versions, 105 entitlements.
* `config/vita-server.php` — feature flags (allow dev token, package
  storage driver, etc.).
* `.htaccess` (root)            — subdirectory routing + source code guard.
* `public/.htaccess`            — Laravel front controller.
