MandelBlogStack / Ocyan Coyote
==============================

Coyote is a Wagtail-first content and styling plugin for the MandelBlogStack /
Ocyan ecosystem. It provides:

- reusable StreamField blocks for marketing and webshop-oriented pages
- curated page models for Coyote home and contact pages
- site-level style settings in Wagtail admin
- front-end theme extensions for ``oxyan.themes`` and
  ``ocyan.plugin.barebone``

It is best understood as a presentation/content system plugin, not a standalone
application.

What Coyote owns
----------------

Coyote contributes the following pieces to a host project:

- ``StyleSettings`` site settings via Wagtail settings
- ``CoyoteHomePage`` and ``CoyoteContactPage`` page models
- StreamField block libraries for headers, content sections, and footers
- admin widgets for visual choices, icons, color pickers, and font selection
- template fragments and SCSS/JS assets used by the Coyote page system

How it fits into MandelBlogStack
--------------------------------

Coyote sits on top of the wider Ocyan stack. It is not intended to run in
isolation.

Required dependencies
~~~~~~~~~~~~~~~~~~~~~

- ``Wagtail`` for pages, blocks, admin, and site settings
- ``ocyan.plugin.wagtail`` for current-request middleware, localization
  helpers, and the shared ``AbstractBasePage`` model
- ``oxyan.themes`` for theme defaults and theme extension support
- ``wagtail-roadrunner`` for shared tags and layout assumptions

Current optional / host-specific assumptions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

These are not cleanly decoupled yet and should be treated as integration
assumptions of the current stack:

- Oscar catalogue templates and stock display partials
- a contact form handler exposed as ``contact_form:contact-form-handler``
- surrounding host templates such as ``layout.html`` and ``base.html``
- Roadrunner template tags used by some block templates

Current hardening status:

- Roadrunner unique-ID dependency has been removed from the accordion template;
  Coyote now provides its own ``get_unique_id`` template tag
- missing Oscar stock/field partials now degrade to empty output or simpler
  field rendering instead of raising template errors
- product slider markup no longer requires
  ``oscar/catalogue/partials/product.html`` to exist just to render the block
- missing ``contact_form`` URL configuration now degrades to a clear
  unavailable message instead of a hard template failure
- Wagtail style settings labels and help text now use client-neutral English
  copy and translation wrappers without altering the existing database schema

If those integrations are missing, Coyote now degrades more safely, but the
affected blocks still provide their best experience inside the full
MandelBlogStack.

Theme integration
-----------------

The plugin registers a front extension into:

- ``oxyan.themes``
- ``ocyan.plugin.barebone``

The extension currently injects optional font imports into the base theme
template. Coyote does not own the full outer page shell; it extends the active
theme/layout system.

Assets and runtime ownership
----------------------------

Current asset layout is mixed:

- public-facing SCSS lives under ``ocyan/plugin/coyote/static/coyote/``
- admin bundles live under ``ocyan/plugin/coyote/static/wagtailadmin/coyote/``
- admin widgets also vendor jQuery and Select2 assets for style/font controls
- webpack builds the admin bundle from the ``js/`` sources

Current source-of-truth notes:

- public templates reference dedicated Coyote stylesheet partials
- admin assets are built from ``js/`` into the committed
  ``static/wagtailadmin/coyote`` bundle output
- the existing ``webpack.config.js`` / ``prd.config.js`` path only builds the
  admin bundle and does not ship compiled public CSS artifacts
- public slider bootstrapping now lives in ``static/coyote/js/page_sliders.js``
  and ``static/coyote/js/slider.js`` instead of inline page template scripts

Public CSS contract
~~~~~~~~~~~~~~~~~~~

Coyote now ships compiled public CSS fallback/default assets under stable
plugin static paths:

- ``static/coyote/css/base.css``
- ``static/coyote/css/homepage/base.css``
- ``static/coyote/css/contact/base.css``

Those compiled files are the default runtime assets loaded by:

- ``templates/coyote/partials/styles/base_styles.html``
- ``templates/coyote/partials/styles/home_styles.html``
- ``templates/coyote/partials/styles/contact_styles.html``

SCSS source-of-truth
~~~~~~~~~~~~~~~~~~~~

SCSS remains the source of truth for public styling:

- ``static/coyote/base.scss``
- ``static/coyote/homepage/base.scss``
- ``static/coyote/contact/base.scss``

Those entrypoints depend on the MandelBlogStack theme Sass function layer from
``oxyan.themes`` and are compiled against the active theme definitions.

Host override / rebuild contract
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The host stack may intentionally override or rebuild the shipped public CSS,
but that is now an explicit choice rather than an implicit runtime dependency.

Safe host options:

- override the Coyote stylesheet partial templates in the host project
- rebuild the compiled CSS files from the same SCSS entrypoints using the
  existing ``django-libsass`` + ``oxyan.themes`` Sass function path
- replace the shipped CSS with host-specific compiled equivalents while keeping
  the SCSS entrypoints source-controlled in this plugin

The plugin does not introduce a second build system for this. The verified
compile path remains the MandelBlogStack Django/libsass stack already used for
theme-aware Sass functions.

Public asset ownership
~~~~~~~~~~~~~~~~~~~~~~

Coyote owns these public SCSS entrypoints:

- ``static/coyote/base.scss``
- ``static/coyote/homepage/base.scss``
- ``static/coyote/contact/base.scss``

and now also ships verified compiled fallback/default assets under:

- ``static/coyote/css/base.css``
- ``static/coyote/css/homepage/base.css``
- ``static/coyote/css/contact/base.css``

That removes the legacy runtime requirement to serve public ``text/x-scss``
directly while still preserving SCSS as the editable source.

Packaging notes
---------------

- package name: ``ocyan.plugin.coyote``
- AppConfig label: ``coyote``
- includes templates/static files through ``include_package_data=True`` and
  ``graft ocyan`` in ``MANIFEST.in``

Current limitations
-------------------

- tightly coupled to parts of the MandelBlogStack host project
- minimal automated coverage outside Google Fonts utility behavior
- repo historically accumulated local build/runtime junk; Phase 1 hardening
  keeps that out of Git going forward
- migrations include state-sensitive custom logic and are intentionally left
  untouched in this phase
- migrations ``0024`` and ``0025`` form a coupled database/state transition for
  the ``AbstractBasePage`` inheritance switch; they should be treated as a
  reviewed chain and not rewritten casually
- several older migrations still import live ``oxyan.themes.definitions.theme``
  defaults; this remains a legacy risk and must not be copied into any future
  migration pattern
- editor-facing copy is still partly Dutch and not fully neutral for all client
  deployments in migration-sensitive StreamField definitions and legacy
  migrations, which were intentionally left unchanged in this phase
- some templates still need accessibility hardening in future phases

Migration and compatibility notes
---------------------------------

Migration caveats
~~~~~~~~~~~~~~~~~

- ``0024_remove_coyotecontactpage_page_ptr_and_more`` performs conditional
  database operations, including a SQLite-specific table rebuild path.
- ``0025_remove_coyotecontactpage_page_ptr_and_more`` carries the matching
  state-only changes through ``SeparateDatabaseAndState``.
- Those migrations should stay paired in the history. If page inheritance needs
  further changes later, add a new migration rather than editing either file.
- Historical migrations from ``0010`` through ``0021`` include imports from
  ``oxyan.themes.definitions.theme``. They are preserved for compatibility, but
  future migrations should freeze defaults directly in the migration file
  instead of importing live theme definitions.

Migration policy
~~~~~~~~~~~~~~~~

Historical migrations are treated as immutable unless there is a very strong,
reviewed reason to intervene. In practice that means:

- do not rewrite the existing ``0010`` / ``0014`` / ``0017`` / ``0018`` /
  ``0019`` / ``0020`` / ``0021`` legacy migration files
- do not edit ``0024`` or ``0025`` casually; they are a coupled historical
  database/state transition and must be treated as a reviewed pair
- do not add any new migration that imports live runtime values from
  ``oxyan.themes.definitions.theme``
- for future migrations, freeze literal defaults directly into the migration
  file instead of importing them from runtime modules
- if future schema or data changes need theme-derived values, resolve and
  freeze them at migration creation time rather than at migration execution

This policy is intentionally conservative: freeze the future without rewriting
the past.

Current compatibility hardening
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- Coyote-owned telepath/widget adapter imports now use the current Wagtail
  admin import paths.
- Optional integrations with Oscar, ``contact_form``, and Roadrunner still
  assume the full MandelBlogStack for best results, but missing pieces degrade
  more safely than before.
- Remaining Wagtail deprecation warnings currently come from external stack
  components such as ``wagtail-roadrunner``, not from the Coyote-owned adapter
  path updated here.

Recommended checks
------------------

Focused plugin checks used during hardening:

.. code-block:: bash

   git diff --check
   ruff check .
   black --check .
   /Users/motolaniolaiya/kitchensink/bin/manage check
   /Users/motolaniolaiya/kitchensink/bin/manage makemigrations --check --dry-run coyote

For smoke tests:

.. code-block:: bash

   DJANGO_SETTINGS_MODULE=ocyan.plugin.coyote.test_settings \
   /Users/motolaniolaiya/kitchensink/.venv/bin/python -m django test \
   --testrunner=django.test.runner.DiscoverRunner ocyan.plugin.coyote.tests

Recommended isolated test path
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

For fast deterministic plugin verification, prefer the plugin-local settings
module via the host ``bin/manage`` bootstrap:

.. code-block:: bash

   cd /Users/motolaniolaiya/kitchensink
   DJANGO_SETTINGS_MODULE=ocyan.plugin.coyote.test_settings \
   bin/manage test \
   ocyan.plugin.coyote.tests.test_smoke \
   ocyan.plugin.coyote.tests.test_utils

That isolated path keeps the Coyote smoke/unit suite out of the full Kitchensink
URL tree and avoids the monolithic test database setup that is unrelated to the
plugin itself.

Integration checks
~~~~~~~~~~~~~~~~~~

Keep the broader host validation separate:

.. code-block:: bash

   cd /Users/motolaniolaiya/kitchensink
   bin/manage check
   bin/manage makemigrations --check --dry-run coyote
