/root/jfmsrv01-build/RULES.md
# jfmsrv01 — Project Rules, Standards and Procedures
# =========================================================
# Version: 2026-05-28
# Server: jfmsrv01 (192.168.100.197)
# Maintainer: Simon / JFM Communications
#
# These rules must be followed by every developer and every AI session
# working on any project on this server. They exist to prevent breaking
# changes, context overload, and lost procedures.
# =========================================================
═══════════════════════════════════════════════════════════════
SECTION 1 — CONTEXT LOADING STRATEGY
═══════════════════════════════════════════════════════════════
The goal is to load only what is needed for the current task.
Never dump everything into a new chat. Context overload causes
AI to lose earlier instructions and make mistakes.
STARTING A NEW CHAT — MINIMUM REQUIRED CONTEXT
───────────────────────────────────────────────
Always start a new chat with these three files only:
1. HANDOVER.md — current state, what is built, what is next
2. CHANGELOG.md — recent changes and decisions
3. RULES.md — this file (so rules are never forgotten)
These three files are always available for download from the
handoff portal at:
http://192.168.100.197:9002/vqngx6j8dc9q1lvt7g2a7a646q2t/
ADDING CONTEXT ON DEMAND
────────────────────────
Only add additional files when the task requires them.
Working on mainsite (Statamic)?
Add: mainsite/route-list.txt, mainsite/error-log-*.txt
Working on admin panel (Filament)?
Add: admin/route-list.txt, admin/migrations.txt,
admin/error-log-*.txt
Working on transcription platform?
Add: transcription/route-list.txt, transcription/migrations.txt,
transcription/services.html, transcription/events.html,
transcription/error-log-*.txt
Database work?
Add: the relevant database-schema.html for that project only
Server/infrastructure work?
Add: server/status.html, server/nginx-config.html
Debugging an error?
Add: the relevant error-log-*.html (unique name, no cache issues)
Add: the relevant route-list.txt
NEVER load into context:
- vendor/ directory contents
- node_modules/ contents
- Full database dumps
- .env files (use sanitised versions from handoff portal)
- composer.lock (too large, not useful for AI)
- Multiple projects at once unless the task spans them
═══════════════════════════════════════════════════════════════
SECTION 2 — MODULAR ARCHITECTURE RULES
═══════════════════════════════════════════════════════════════
Every project on this server must be modular. A change to one
module must never break another module.
RULE M1 — ONE MODULE, ONE RESPONSIBILITY
─────────────────────────────────────────
Each module does one thing. It does not reach into another
module's internals. Examples:
CORRECT: TranscriptionModule fires TranscriptionCompleted event
DocumentModule listens for TranscriptionCompleted
INCORRECT: TranscriptionModule calls DocumentModule::generate() directly
CORRECT: StorageService handles all file paths
INCORRECT: A controller builds file paths inline
RULE M2 — COMMUNICATE THROUGH INTERFACES, NOT INTERNALS
────────────────────────────────────────────────────────
Modules communicate through:
- Events (fire and forget)
- Service classes with defined public methods
- Shared database tables with agreed column contracts
Modules must never:
- Call private methods of another module
- Directly query another module's primary tables
- Share a service class that does two unrelated things
RULE M3 — FEATURE FLAGS BEFORE DISABLING
─────────────────────────────────────────
Never delete or comment out a module to disable it.
Always use feature flags. A disabled module must:
- Disappear from all menus and navigation
- Return 403 or 404 at route level
- Not run any background jobs
- Not confuse users with broken UI
RULE M4 — NO SHARED STATE BETWEEN PROJECTS
────────────────────────────────────────────
The three projects on this server (mainsite, admin, transcription)
are completely independent applications. They must never:
- Share a database (each has its own)
- Share a storage directory
- Share session state
- Share vendor/ or node_modules/
- Call each other's APIs without explicit documented integration
RULE M5 — EVERY MODULE HAS A HEALTH CHECK
──────────────────────────────────────────
Every significant module must expose a health check that can be
called from the diagnostics script. Health checks must:
- Return pass/fail
- Check database connectivity
- Check storage accessibility
- Check queue worker status if applicable
[REDACTED SECRET-LIKE LINE]
RULE M6 — MIGRATIONS ARE PERMANENT
────────────────────────────────────
Never edit an existing migration file once it has been run in
any environment. Always create a new migration to alter a table.
Editing old migrations causes schema drift and breaks deployments.
RULE M7 — NEVER HARD-CODE FIRM OR TENANT DATA
───────────────────────────────────────────────
(Transcription platform specific)
No firm name, firm ID, file path, API key, email address, or
branding value may ever be hard-coded in application code.
Everything firm-specific lives in the database or .env.
RULE M8 — STORAGE ABSTRACTION IS MANDATORY
────────────────────────────────────────────
(Transcription platform specific)
All file operations must go through StorageService.
No controller, job, or service may build its own file path.
StorageService validates every path against the firm's permitted
base path to prevent path traversal attacks.
═══════════════════════════════════════════════════════════════
SECTION 3 — PATCH AND CHANGE PROCEDURES
═══════════════════════════════════════════════════════════════
Every change, no matter how small, follows this workflow.
No exceptions. This prevents broken deployments and lost context.
RULE P1 — ALWAYS RUN PATCH PRE BEFORE CHANGING ANYTHING
─────────────────────────────────────────────────────────
Before making any change:
sudo bash /opt/jfmsrv01/scripts/patch.sh pre "description of what you are about to do"
This takes a source backup and runs a pre-patch smoke test.
If the smoke test fails before you start, fix it first.
RULE P2 — ALWAYS RUN PATCH POST AFTER CHANGING ANYTHING
─────────────────────────────────────────────────────────
After making any change:
sudo bash /opt/jfmsrv01/scripts/patch.sh post "description of what you did"
This:
- Clears all caches
- Runs migrations if any
- Reloads services
- Runs post-patch smoke test
- Adds a changelog entry
- Publishes the handoff portal automatically
If DB schema changed:
sudo bash /opt/jfmsrv01/scripts/patch.sh post "description" db
The "db" argument triggers a full database backup.
RULE P3 — FIX IN PLACE, DO NOT ROLL BACK UNLESS CRITICAL
──────────────────────────────────────────────────────────
If a patch causes an error, try to fix it in place first.
Only roll back if:
- The site is completely down
- Data is at risk
- The fix would take longer than the outage can tolerate
If rolling back:
1. Restore from the pre-patch source backup
2. Restore database if schema changed
3. Clear caches
4. Run smoke test
5. Log the rollback in CHANGELOG.md with the reason
RULE P4 — ONE CHANGE AT A TIME
───────────────────────────────
Do not bundle multiple unrelated changes into one patch.
Each patch should do one thing. This makes debugging easier
and rollbacks safer.
RULE P5 — DATABASE CHANGES REQUIRE EXTRA CARE
───────────────────────────────────────────────
Any change that touches database schema must:
1. Create a new migration (never edit existing)
2. Test the migration on a non-production environment first if possible
3. Take a database backup before applying (use "db" argument in patch.sh)
4. Verify migration ran cleanly in the smoke test
5. Update database-schema.html in the handoff portal
RULE P6 — NGINX CHANGES REQUIRE A SYNTAX TEST FIRST
─────────────────────────────────────────────────────
Before reloading Nginx after any config change:
nginx -t
Never reload Nginx with a broken config. It will take down all
sites on the server.
[REDACTED SECRET-LIKE LINE]
────────────────────────────────────────────────────────────
[REDACTED SECRET-LIKE LINE]
never appear in:
- Any log file at any log level
- CHANGELOG.md or HANDOVER.md
- Any file published to the handoff portal
- Any git commit message or diff
- Any ZIP file exported for handoff
The sanitise() function in publish_handoff.sh redacts known
patterns, but the developer is responsible for not logging
[REDACTED SECRET-LIKE LINE]
═══════════════════════════════════════════════════════════════
SECTION 4 — HANDOVER PROCEDURES
═══════════════════════════════════════════════════════════════
RULE H1 — HANDOVER.md MUST ALWAYS BE CURRENT
──────────────────────────────────────────────
HANDOVER.md is the single most important file on this server.
It must always reflect the current state of the system.
Update HANDOVER.md whenever:
- A new feature is completed
- A module is added or removed
- The architecture changes
- A key decision is made
- A new dependency is added
- A third-party service is integrated
- Anything that a new developer would need to know
HANDOVER.md must always contain:
- What is currently built and working
- What is in progress
- What is next
- All key file locations
- All important commands
- Architecture decisions and the reasons for them
- Any known issues or technical debt
- Any pending tasks
RULE H2 — CHANGELOG.md MUST HAVE AN ENTRY FOR EVERY CHANGE
────────────────────────────────────────────────────────────
Every patch gets a changelog entry. Minimum format:
## YYYY-MM-DD - Brief description
### Changed
- What changed and why
### Fixed (if applicable)
- What was broken and how it was fixed
### Added (if applicable)
- New features or modules
The patch.sh post command adds a basic entry automatically.
Always expand it with meaningful detail.
RULE H3 — HANDOFF PORTAL MUST BE ACCESSIBLE BEFORE ENDING A SESSION
─────────────────────────────────────────────────────────────────────
Before ending any work session, verify:
1. http://192.168.100.197:9002/vqngx6j8dc9q1lvt7g2a7a646q2t/ loads
2. HANDOVER.md is updated
3. CHANGELOG.md has the latest entry
4. Smoke test passes
5. All services are running
If starting a new AI chat mid-project, always download the
latest HANDOVER.md, CHANGELOG.md, and RULES.md from the
handoff portal first.
RULE H4 — ARCHITECTURE DECISIONS MUST BE RECORDED
───────────────────────────────────────────────────
When a significant technical decision is made (stack choice,
database design, module structure, API design, integration
approach), record it in HANDOVER.md under "Architecture Decisions"
with the date and the reason. Future developers need to understand
why things were built the way they were, not just what was built.
RULE H5 — THE HANDOFF PORTAL AUTO-UPDATES ON EVERY PATCH
──────────────────────────────────────────────────────────
The publish_handoff.sh script runs automatically after every
patch.sh post. It regenerates all HTML files, error logs (with
unique filenames to prevent caching), source ZIPs, and schema
files. No manual publish step is required.
If you need to trigger a manual publish:
sudo bash /opt/jfmsrv01/scripts/publish_handoff.sh
If schema or data changed:
sudo bash /opt/jfmsrv01/scripts/publish_handoff.sh db
═══════════════════════════════════════════════════════════════
SECTION 5 — DEPLOYMENT STANDARDS
═══════════════════════════════════════════════════════════════
RULE D1 — SERVER IS DEDICATED
───────────────────────────────
jfmsrv01 is a dedicated server. No unrelated applications
should be installed here. If a new application is needed,
it gets its own server or its own isolated project directory
with its own database, storage, and Nginx vhost.
RULE D2 — EVERY PROJECT HAS ITS OWN NGINX VHOST
─────────────────────────────────────────────────
Each project gets its own file in /etc/nginx/sites-available/.
Never put two projects in the same server block.
Never use the default Nginx site for production content.
Current vhosts:
/etc/nginx/sites-available/mainsite — Statamic (port 80)
/etc/nginx/sites-available/admin — Filament (port 8080)
/etc/nginx/sites-available/handoff — Handoff portal (port 9002)
/etc/nginx/sites-available/jfmsrv01 — Transcription (future)
RULE D3 — EVERY PROJECT HAS ITS OWN DATABASE
──────────────────────────────────────────────
Current databases:
jfmsrv01 — transcription platform
mainsite — Statamic website
admin — Filament admin panel
Never share a database between projects. If two projects need
the same data, replicate it or create an explicit API.
RULE D4 — EVERY PROJECT HAS ITS OWN STORAGE PATH
──────────────────────────────────────────────────
/var/www/mainsite — Statamic application and content
/var/www/admin — Filament application
/var/www/handoff — Handoff portal (static HTML only)
/opt/jfmsrv01/ — Transcription platform application
/data/jfmsrv01/ — Transcription platform data files
No project may read or write another project's directory.
RULE D5 — TLS IS MANDATORY FOR ANY PUBLIC-FACING SERVICE
──────────────────────────────────────────────────────────
Any service exposed to the internet must use TLS.
Internal-only services (handoff portal, admin panel) may use
plain HTTP on internal IPs only while they remain internal.
When a domain is pointed at this server and a service goes public,
a Let's Encrypt certificate must be provisioned first.
RULE D6 — FIREWALL CHANGES MUST BE DOCUMENTED
───────────────────────────────────────────────
Any change to ufw rules must be recorded in CHANGELOG.md.
Before opening any port externally, confirm:
- The service is ready for public access
- TLS is configured
- Rate limiting is in place if needed
- The change is documented
RULE D7 — QUEUE WORKERS MUST ALWAYS RUN
─────────────────────────────────────────
Queue workers are managed by Supervisor.
After any deployment or server restart, verify:
supervisorctl status
All jfmsrv01-worker processes must show RUNNING.
If any are stopped, restart them:
supervisorctl restart jfmsrv01-worker:*
RULE D8 — REDIS PERSISTENCE IS NON-NEGOTIABLE
───────────────────────────────────────────────
Redis is configured with AOF persistence. This must never be
disabled. A Redis restart without persistence would silently
drop all pending queue jobs, which in a legal workflow could
mean lost work.
RULE D9 — CLAMAV DEFINITIONS MUST STAY CURRENT
────────────────────────────────────────────────
ClamAV definitions are updated daily via freshclam cron.
The admin diagnostics page shows definition age.
If definitions are more than 3 days old, investigate the
freshclam service. A stale scanner is worse than no scanner
because it gives false confidence.
═══════════════════════════════════════════════════════════════
SECTION 6 — SECURITY RULES
═══════════════════════════════════════════════════════════════
RULE S1 — .ENV FILES ARE NEVER SHARED OR COMMITTED
────────────────────────────────────────────────────
.env files contain secrets. They must never be: [REDACTED]
- Committed to git
- Copied to the handoff portal
- Shared in chat
- Included in source ZIPs
- Visible in log files
Always use the sanitised .env view from the handoff portal
when sharing config structure with an AI or developer.
RULE S2 — ROOT SSH IS ENABLED BUT MUST BE REVIEWED PERIODICALLY
─────────────────────────────────────────────────────────────────
[REDACTED SECRET-LIKE LINE]
for administrative convenience. This is acceptable while the
server is internal-only.
Before exposing SSH to the internet:
[REDACTED SECRET-LIKE LINE]
- Switch to key-based authentication only
- Consider changing SSH to a non-standard port
- Review /etc/ssh/sshd_config
[REDACTED SECRET-LIKE LINE]
RULE S3 — AUDIT LOG ALL IMPORTANT ACTIONS
───────────────────────────────────────────
(Transcription platform specific)
Every action that touches a firm's data, settings, or users
must be logged via AuditService::log(). This includes:
- File uploads and downloads
- Document approvals
- Template changes
- User logins
- Support impersonation
- Settings changes
- AI provider changes
The audit log is tenant-scoped. A firm admin can see their
own firm's audit log but not another firm's.
RULE S4 — PATH TRAVERSAL PROTECTION IS MANDATORY
──────────────────────────────────────────────────
(Transcription platform specific)
All file paths resolved for firm storage must be validated
against the firm's permitted base path before any operation.
StorageService does this automatically. Never bypass it.
RULE S5 — AI PROVIDERS MUST RESPECT FIRM PRIVACY TIER
───────────────────────────────────────────────────────
(Transcription platform specific)
Every AI call must go through AiService which enforces the
firm's configured privacy tier:
Tier 1 — on-premise only (no data leaves firm)
Tier 2 — private API with no-training guarantee
Tier 3 — shared API (standard terms)
A firm configured at Tier 2 must never have its data sent to
a Tier 3 provider, even if the router recommends it.
AiService blocks this and logs the attempt.
RULE S6 — BACKUP ENCRYPTION
─────────────────────────────
Database backups containing real data must be encrypted before
being stored or transferred off-server. Schema-only SQL files
published to the handoff portal contain no data and do not need
[REDACTED SECRET-LIKE LINE]
═══════════════════════════════════════════════════════════════
SECTION 7 — CODE STANDARDS
═══════════════════════════════════════════════════════════════
RULE C1 — ONE SHARED THEME, NOT PAGE-SPECIFIC CSS
───────────────────────────────────────────────────
Each project must have one shared CSS theme/design system.
Page-specific CSS overrides must be minimal and justified.
Never create a new stylesheet for a single page when a utility
class or shared component would suffice.
[REDACTED SECRET-LIKE LINE]
─────────────────────────────
[REDACTED SECRET-LIKE LINE]
inline in code. All secrets come from: [REDACTED]
- The .env file (via config() helper in Laravel)
- Environment variables
[REDACTED SECRET-LIKE LINE]
[REDACTED SECRET-LIKE LINE]
RULE C3 — EVERY BACKGROUND JOB MUST HAVE A FIRM CONTEXT
─────────────────────────────────────────────────────────
(Transcription platform specific)
Every queue job that processes firm data must carry the firm_id.
A job must never run without knowing which firm it belongs to.
This prevents cross-firm data leakage in background processing.
RULE C4 — FEATURE FLAGS WRAP INCOMPLETE FEATURES
──────────────────────────────────────────────────
Any feature that is not yet complete must be wrapped in a
feature flag and disabled. This allows the codebase to be
deployed safely while work continues.
Never push broken or incomplete UI without a feature flag hiding it.
RULE C5 — ARTISAN COMMANDS FOR ADMIN TASKS
────────────────────────────────────────────
[REDACTED SECRET-LIKE LINE]
running diagnostics) must be done through Artisan commands or
Tinker, not by editing the database directly. Direct database
edits bypass model events, observers, and audit logging.
RULE C6 — MIGRATIONS MUST BE REVERSIBLE WHERE POSSIBLE
────────────────────────────────────────────────────────
Every migration should have a working down() method where
practical. This allows rollbacks to be tested. If a migration
is truly irreversible (e.g. deleting data), document why in
a comment inside the migration.
RULE C7 — COMPOSER AND NPM PACKAGES MUST BE JUSTIFIED
───────────────────────────────────────────────────────
Every new package added must have a clear reason. Prefer
packages that are:
- Actively maintained
- Widely used in the Laravel ecosystem
- Have no critical known vulnerabilities
- Do not conflict with existing packages
Record new significant packages in CHANGELOG.md.
═══════════════════════════════════════════════════════════════
SECTION 8 — PROJECT DIRECTORY REFERENCE
═══════════════════════════════════════════════════════════════
SERVER INFRASTRUCTURE
─────────────────────
/opt/jfmsrv01/scripts/ Admin scripts
/opt/jfmsrv01/scripts/CHANGELOG.md Change history
/opt/jfmsrv01/scripts/HANDOVER.md Current state
/opt/jfmsrv01/scripts/RULES.md This file
/opt/jfmsrv01/scripts/patch.sh Patch workflow
/opt/jfmsrv01/scripts/backup.sh Backup script
/opt/jfmsrv01/scripts/smoke_test.sh Smoke test
/opt/jfmsrv01/scripts/diagnostics.sh Diagnostics JSON
/opt/jfmsrv01/scripts/publish_handoff.sh Handoff publisher
[REDACTED SECRET-LIKE LINE]
MAINSITE (STATAMIC)
────────────────────
/var/www/mainsite/ Application root
/var/www/mainsite/.env Configuration (never share)
/var/www/mainsite/content/ Statamic content files
/var/www/mainsite/resources/ Views and assets
/var/www/mainsite/config/statamic/ Statamic configuration
/var/www/mainsite/users/ Statamic user YAML files
/etc/nginx/sites-available/mainsite Nginx config
ADMIN PANEL (FILAMENT)
───────────────────────
/var/www/admin/ Application root
/var/www/admin/.env Configuration (never share)
/var/www/admin/app/Filament/ Filament resources/pages/widgets
/var/www/admin/app/Models/ Eloquent models
/var/www/admin/database/migrations/ Database migrations
/etc/nginx/sites-available/admin Nginx config
HANDOFF PORTAL
───────────────
/var/www/handoff/public/ Static HTML output
/var/www/handoff/public/vqngx6j8dc9q1lvt7g2a7a646q2t/ Public slug
/etc/nginx/sites-available/handoff Nginx config
URL: http://192.168.100.197:9002/vqngx6j8dc9q1lvt7g2a7a646q2t/
TRANSCRIPTION PLATFORM (NOT YET STARTED)
──────────────────────────────────────────
/opt/jfmsrv01/app/ Laravel application (future)
/data/jfmsrv01/firms/ Per-firm file storage (future)
/data/jfmsrv01/quarantine/ Quarantined files (future)
/etc/nginx/sites-available/jfmsrv01 Nginx config (future)
/etc/supervisor/conf.d/jfmsrv01-worker.conf Queue workers
═══════════════════════════════════════════════════════════════
SECTION 9 — QUICK REFERENCE COMMANDS
═══════════════════════════════════════════════════════════════
DAILY OPERATIONS
─────────────────
# Check all services
systemctl status nginx postgresql redis-server clamav-daemon supervisor
# Check queue workers
supervisorctl status
# Run smoke test
sudo bash /opt/jfmsrv01/scripts/smoke_test.sh
# View diagnostics
sudo bash /opt/jfmsrv01/scripts/diagnostics.sh
# Tail error logs
tail -50 /var/www/mainsite/storage/logs/laravel.log
tail -50 /var/www/admin/storage/logs/laravel.log
tail -50 /var/log/nginx/error.log
PATCH WORKFLOW
───────────────
# Before any change
sudo bash /opt/jfmsrv01/scripts/patch.sh pre "what you are doing"
# After any change (source only)
sudo bash /opt/jfmsrv01/scripts/patch.sh post "what you did"
# After any change that touched the database
sudo bash /opt/jfmsrv01/scripts/patch.sh post "what you did" db
BACKUPS
────────
sudo bash /opt/jfmsrv01/scripts/backup.sh source
sudo bash /opt/jfmsrv01/scripts/backup.sh database
sudo bash /opt/jfmsrv01/scripts/backup.sh files
sudo bash /opt/jfmsrv01/scripts/backup.sh full
HANDOFF PORTAL
───────────────
# Manual publish
sudo bash /opt/jfmsrv01/scripts/publish_handoff.sh
# Manual publish with DB backup
sudo bash /opt/jfmsrv01/scripts/publish_handoff.sh db
# Access URL
http://192.168.100.197:9002/vqngx6j8dc9q1lvt7g2a7a646q2t/
ARTISAN (run from project directory as www-data or jfmsrv01)
────────────────────────────────────────────────────────────────────
cd /var/www/mainsite && php artisan ...
cd /var/www/admin && php artisan ...
cd /opt/jfmsrv01/app && php artisan ...
NGINX
──────
nginx -t # test config before reloading
systemctl reload nginx # reload (no downtime)
systemctl restart nginx # restart (brief downtime)
POSTGRESQL
───────────
sudo -u postgres psql # postgres shell
psql -U jfmsrv01 -h 127.0.0.1 mainsite # mainsite DB
psql -U jfmsrv01 -h 127.0.0.1 admin # admin DB
REDIS
──────
[REDACTED SECRET-LIKE LINE]
[REDACTED SECRET-LIKE LINE]
[REDACTED SECRET-LIKE LINE]
═══════════════════════════════════════════════════════════════
SECTION 10 — KNOWN ISSUES AND TECHNICAL DEBT
═══════════════════════════════════════════════════════════════
Update this section whenever a known issue is identified.
Format: DATE | SEVERITY | DESCRIPTION | WORKAROUND
2026-05-28 | LOW | Statamic and Filament cannot coexist in the same
Laravel app due to auth guard conflicts. Resolved by
running as two separate applications on different ports.
No further action needed unless a unified SSO is required.
[REDACTED SECRET-LIKE LINE]
Acceptable for internal-only server. Must be reviewed
before any public SSH exposure.
2026-05-28 | INFO | The transcription platform Laravel skeleton at
/opt/jfmsrv01/app has not yet been deployed to
Nginx. Phase 2 of the build plan covers this.
═══════════════════════════════════════════════════════════════
SECTION 11 — PROJECTS STATUS
═══════════════════════════════════════════════════════════════
Update this section after every significant milestone.
MAINSITE (STATAMIC)
────────────────────
Status: RUNNING
URL: http://192.168.100.197 (internal)
CP: http://192.168.100.197/cp
Version: Statamic v6.20.0 / Laravel 13.12.0
Database: mainsite (PostgreSQL)
Users: simon@jfmcommunications.com.au (super)
Notes: File-based user driver. Public port forwarding
controlled by Untangle firewall.
ADMIN PANEL (FILAMENT)
───────────────────────
Status: RUNNING
URL: http://192.168.100.197:8080/admin (internal)
Version: Filament v5.6.6 / Laravel 13.12.0
Database: admin (PostgreSQL)
Users: simon@jfmcommunications.com.au
Notes: Separate app from mainsite due to auth conflicts.
Separate FilamentUser model/table.
HANDOFF PORTAL
───────────────
Status: RUNNING
URL: http://192.168.100.197:9002/vqngx6j8dc9q1lvt7g2a7a646q2t/
Notes: IP whitelisted to 192.168.0.0/16.
Auto-updates on every patch.sh post.
Error logs use unique filenames to prevent caching.
LEGAL TRANSCRIPTION PLATFORM
──────────────────────────────
Status: ON HOLD — foundation scripts ready, not yet deployed
Scripts: /jfmsrv01-build/ on server
01_storage_layout.sh — next to run when resuming
Notes: All planning documents complete. Server infrastructure
ready. Resume when required by running scripts in order:
01_storage_layout.sh
02_app_skeleton.sh
03_admin_safety_tools.sh
04_first_firm.sh