Deployment#
Scheduled tasks#
Without them the system does not work properly. Tasks are presenters in
app/UI/Cron/, triggered by an HTTP request with a token.
| Group | What it does | How often |
|---|---|---|
| E-mail queue | sends | every few minutes |
| Expiry | warnings and deletion of expired adverts and listings | daily |
| Recalculations | category counts, prices | 10–15 min |
| Saved searches | sends alerts | continuously or daily |
| Payments | follow-up invoicing, evaluation | continuously |
| Invoice scheduler | recurring invoicing | daily |
| Elasticsearch | sync and a nightly reindex | 10 min / daily |
| Sitemaps | generation | as needed |
Without scheduled tasks the problems surface only after weeks
Adverts never expire, counts stop matching, emails pile up. Nothing reports it. After deploying, check the tasks actually run.
Nothing ever executes in www/uploads/
Uploaded files live in the public tree and keep their extension. The application
rejects dangerous extensions (php, phtml, phar, cgi, sh, .htaccess …) in any
part of the name, but the web server is the second line of defence.
Apache reads the versioned www/uploads/.htaccess (PHP engine off, script
extensions denied). It needs AllowOverride All (or at least FileInfo Options Limit)
for the site directory.
nginx ignores .htaccess. Add this to the server block before the generic
location ~ \.php$:
After deployment verify that an uploaded test.php.txt in uploads/ is served as
text, not executed.
Concurrency is handled by a lock
Two instances of the same task will not run. But do not schedule them needlessly often — a long task blocks the next one.
Production settings#
| Item | Setting |
|---|---|
| Debug mode | off |
| Error display | off, log instead |
| Cache | on |
docs/sql/ |
not reachable from outside |
| Gateway credentials | in local.neon only |
www/uploads/ |
no script execution |
The debug panel prints the configuration, credentials included
Left on in production, the keys to payment gateways and other services end up in the page source. Verify it is off.
How debug mode is decided#
The production default is off; it is switched on explicitly.
App\Bootstrap::resolveDebugMode() decides in this order:
- the
NETTE_DEBUGenvironment variable —1,true,on,yesturn it on, anything else including0andfalseturns it off, - the existence of the
config/debug-mode.flagfile (not in the repo; on the dev server you create it withtouch), - otherwise off.
The environment variable overrides the flag file
When NETTE_DEBUG is set to anything outside the permitted four values, the flag file
is not read at all. On a machine where the variable is set by accident, touch will
therefore not help.
Building assets#
Use the global sass, not npx sass
Different versions producing different output. The difference shows as small layout shifts nobody connects with the deployment.
Deploying onto an existing database#
Upgrading an older installation inherits more than data — it inherits schema
defects nobody has seen for years. Run the
Database check before deploying; it is read-only
SELECTs and safe against production.
The first query matters most: it lists *_texts translation tables missing their
composite primary key. Without it the database accepts duplicate translations,
and every further seed run adds more.
Automated checks will not find this
SchemaValidator::validateClass compares columns and types, not indexes — a
missing primary key passes it. The only ways to find out are this query, or
the site showing different text than the admin does.
The chapter covers what to do about a finding, with the fix scripts to copy.
Post-deployment checks#
- The home page and signing in.
- One administration listing and one form.
- A test order all the way to dispatch.
- The email queue — is it sending?
- The error log — anything new?
A test order is the best check
It goes through the cart, payment, stock, invoicing and email at once. One pass tests more than an hour of clicking around screens.