2.4 KiB
Frontend context
Read
ai/shared.mdfirst. This file only covers frontend-specific rules.
Project Context
Stack: vanilla PHP templates in views/templates/, plain ES JavaScript in
public/js/, no framework, no build step. Cypress 15 for E2E.
Entry point: public/index.php (Slim app); page templates are rendered
via the existing templating layer.
Code patterns
- Look at existing pages (
home.php/home.js,text.php/text.js,today.php/today.js) for reference before writing anything - Templates:
views/templates/<page>.php, one file per page - Page JS:
public/js/<page>.js, one file per page, paired with the matching template - Testing: Cypress E2E only, mirror existing
cypress/e2e/*.cy.jsstyle (note: this project uses.cy.js, not.cy.ts) - Imports / script tags: keep at the top of the file
- Variable names: explicit, descriptive (e.g.
textnott)
Pre-commit
No JS formatter or linter is configured yet; format manually for consistency with surrounding files. (TODO: wire up format/lint when added.)
Note on commit granularity
Frontend changes are often a template plus its page-level JS counterpart -
commit them together as a single logical unit, per the "one logical change
per commit" rule in shared.md.
LLM anti-patterns
Constructs LLMs default to that this project forbids on the frontend.
| Anti-pattern | Forbidden | Required |
|---|---|---|
| Short variable name | t, n, res, req, e, el, ev |
text, node, response, request, submitEvent, element, clickEvent |
| Em dash in code/comments | // loads texts — owner only |
// loads texts - owner only |
Inline <script> in templates |
<script>doStuff()</script> in a .php template |
put logic in public/js/<page>.js, load via <script src=...> |
| Hardcoded admin URLs in user-facing JS | fetch('/api/admin/...') from a non-admin page JS |
call user-scoped endpoints from user pages, admin endpoints only from admin pages |
| Cypress test logging in as the wrong role | cy.loginAsAdmin() in a non-admin spec |
match the role to the page under test (loginAsUser for /home, /texts; loginAsAdmin for /admin/*) |
cy.request in E2E tests |
cy.request('/api/...') to set up state or assert |
tests must exercise UI - drive via cy.visit/cy.get; if seeding is needed, add it to backend seed data |
When generating code, scan the diff for these patterns before writing it to disk.