# TeXise SaaS migration and upgrade notes

## Baseline

This conversion is based on the supplied `R14.28.12 / R31 Build Fix 4.4` source. It extends the existing editor and trusted Node server rather than replacing them.

The browser-local project/compiler architecture remains authoritative:

```text
local workspace -> browser TeX engine -> browser-local PDF
```

There is no manuscript upload or server-side TeX compile path in this conversion.

## Database schema

The current SaaS schema version is `2` and is tracked in `schema_migrations`.

Fresh installations create, without destructive drops:

- `users`
- `sessions`
- `oauth_accounts`
- `user_settings`
- `projects`
- `license_keys`
- `license_verifications`
- `ai_usage`
- `ai_review_reservations`
- `admin_audit_log`
- `support_tickets`
- compatibility `blogs` and `docs`
- `cms_posts`, `cms_post_content`, `cms_tags`, `cms_post_tags`
- `cms_docs`, `cms_doc_content`, `cms_doc_tags`
- `schema_migrations`

### Legacy-table preservation

Existing `users`, `license_keys`, `support_tickets`, `blogs` and `docs` rows are preserved. Compatibility repair adds missing SaaS columns and indexes in place. It does not blindly drop or recreate existing tables.

Legacy `blogs` and `docs` content is copied/imported into the canonical CMS tables. Legacy rows are retained.

If a legacy table contains duplicate non-empty identity/license values that would make a required unique index unsafe (for example duplicate user emails), migration stops with a clear error. Resolve the duplicate legacy data intentionally, then rerun the idempotent installer. TeXise does not silently merge or delete those rows.

## Administrator migration

If `admin@texise.com` does not exist, a bootstrap administrator is created with the requested initial password `admin`, hashed with bcrypt, and `force_password_change=1`.

New MD5 password hashes are never created. If a legacy administrator row contains a 32-character MD5 hash, the old hash is accepted only for a successful one-time login and is immediately replaced with a bcrypt hash.

Google OAuth is deliberately prevented from claiming or rebinding the password-admin identity through email fallback.

## License migration

`license_keys` retains compatibility fields `id`, `keys`, and `isUsed`, with account/provider/block/quota metadata added.

For authenticated users the server is authoritative for Pro/LTD entitlement, administrator block status and server-funded AI quota. Re-verifying a license cannot clear an administrator block, and a license attached to another active account cannot be silently reassigned.

Anonymous browser activation remains compatible with the existing signed-entitlement system. When the browser is online and refreshes/activates, the MySQL block policy is enforced. A previously issued signed entitlement can still operate during its designed offline grace period because true immediate revocation is impossible while a client is completely offline.

## Project registry migration

The `projects` table stores metadata only:

- account/user ID;
- project public ID/name;
- storage type;
- template identity/version/tier;
- active/archive status;
- timestamps/last opened time.

It stores no `.tex`, `.bib`, images, PDFs, ZIPs, filesystem handles or other project content.

Existing browser workspaces remain local. When an authenticated local workspace is associated with an account record, the cloud public ID is stored only in local workspace metadata. A different device sees the cloud record and asks the user to relink the local folder when necessary.

Removing a project from the account deletes server registry metadata only; it does not delete local files.

## Template migration

The old hard-coded catalogue is replaced by filesystem authority:

```text
texise-templates/free/*
texise-templates/pro/*
```

The existing eight template seeds were materialized under those folders. `scripts/generate-template-manifest.mjs` scans and validates them and atomically writes `texise-templates/templates.json` through a `.tmp` file.

Tier always comes from the parent directory. `template.json` cannot promote/demote itself. Traversal, symlinks, duplicate IDs, invalid slugs, missing entry files, malformed metadata and unsafe/oversized files fail generation without overwriting the last valid manifest.

The generated manifest includes an explicit safe file list so the browser can recursively copy complete nested/binary template projects without directory enumeration APIs.

## URL/application migration

`/projects` is the visible TeXise application home. Bare `/ws` redirects to `/projects`; only hash-bearing deep `/ws#route=...` URLs remain as internal compatibility routing for the mature editor. Canonical SaaS pathname routes are selected before that internal editor router is mounted.

`/projects` uses the existing workspace/filesystem services; it is not a parallel project manager.

Legacy `/doc` and `/doc/:slug` URLs redirect to `/docs` and `/docs/:slug`.

Apache continues to proxy `/api/` and collaboration WebSocket traffic, while SPA fallback supports direct refresh of all canonical frontend routes.

## Theme/design migration

Prefix source was used as a visual reference only. TeXise-owned semantic tokens reproduce its visual character; Prefix branding, copy, backend logic, URLs, analytics and customer content are not runtime dependencies.

ProseMirror remains internal editor machinery. Presentation uses TeXise application chrome while functional ProseMirror selection/cursor/node-view CSS is retained.

STIX Two Text is scoped only to the visual manuscript `.ProseMirror`. It is not a global UI font.

## Upgrade procedure

1. Back up `/etc/texise`, MySQL and the current deployed source/runtime.
2. Place the eight required browser font files in `/var/www/texise.com/fonts/` (or `TEXISE_FONT_SOURCE_DIR`) as documented in `FONT-ASSETS-REQUIRED.md`.
3. Add MySQL/Google/SMTP/shop settings to `/etc/texise/texise.env` as required; existing values are preserved by installer upgrades.
4. Ensure the MySQL database exists, or deliberately opt into database creation with `TEXISE_MYSQL_CREATE_DATABASE=1` and sufficient DB privilege.
5. Run the existing TeXise installer/upgrade workflow. Do not create a parallel deployment workflow.
6. The installer validates configuration, installs staged runtime dependencies, runs idempotent migrations, bootstraps the administrator only if absent, regenerates the template manifest, builds the frontend, validates Apache and performs health checks before considering activation successful.
7. Log into `/admin/login` and change the bootstrap password immediately if this is a fresh installation.
8. Configure the exact Google authorized redirect URI `${TEXISE_APP_URL}/api/auth/google/callback` in the Google Cloud project.
9. Exercise MySQL, Google OAuth, SMTP, template apply and browser editor/compiler flows in the actual deployment environment; these external/runtime flows cannot be fully certified by static source checks alone.

## Rollback principle

The trusted server is staged before activation and keeps a previous runtime for rollback. Frontend production staging and existing TeXise rollback behavior remain in place. Database migrations are additive/idempotent; do not attempt rollback by dropping new tables in production. Restore from a database backup only if a full data rollback is operationally required.

## AI Review writable-state migration

Older TeXise configuration may contain:

```text
TEXISE_AI_REVIEW_AUDIT_DB=/etc/texise/ai-review-audit.sqlite3
```

The hardened service intentionally treats `/etc/texise` as read-only. Upgrade now migrates only that historical TeXise-owned default to:

```text
TEXISE_AI_REVIEW_AUDIT_DB=/var/www/texise.com/public_html/texise-data/audit/ai-review-audit.sqlite3
```

If the old SQLite database exists, it and any `-wal`/`-shm` files are moved at the final service activation boundary and assigned `texise:texise 0640`. Custom administrator database paths are never rewritten automatically.


## SaaS preflight before activation

Install/upgrade now stages the trusted runtime and its pinned server dependencies, then runs a MySQL/migration/admin preflight before replacing the active runtime. Database authentication, missing-database, privilege, migration, or bootstrap-admin failures therefore abort before service activation. The failed health check also prints the recent `texise.service` journal automatically.
