Platform documentation
The CASH Music platform gives all musicians access to tools that let them manage, promote, and sell their music online — all owned and controlled themselves.
The whole thing is designed to work as a freestanding API or integrated with publishing and CMS systems like Wordpress or Drupal. The standard repo contains the core framework, installers, an admin webapp, APIs, demos, and a full suite of tests.
Setup and requirements
One of our goals is for this to run in as many places as possible, so we've worked hard to keep the requirements as minimal as possible:
- PHP 5.2.7+
- PDO and MySQL OR SQLite
- mod_rewrite (for admin)
- fopen wrappers OR cURL
Installation: Just fork/clone this repo, cd into the new /DIY folder, and run:
make install
choosing SQLite will get you up and running fastest. Next just point Apache or MAMP at the /DIY directory and view http://localhost/ in a browser.
There's a web installer for non-coders here. The idea is that we make it easy to deploy on any shared server.
Code standards
When in doubt, code for legibility and easy adoption. Capitalization and CamelCase should be used for class names, camelCase starting with lowercase for function names, and variable names in snake_case (lowercase and underscores.) Indentation has been kept simple — a single hard tab for each level, with curly brackets on the same line as the control statement.
So a simplified file will look something like:
/**
* Description
*
* @package seed.org.cashmusic
* @author CASH Music
* @link http://cashmusic.org/
*
* Copyright (c) 2012, CASH Music
* Licensed under the Affero General Public License version 3.
* See http://www.gnu.org/licenses/agpl-3.0.html
*
*/class ClassName {
protected $variable;
/**
* Function Description
*
* @return value
*/public function functionName($input_variable) {
$variable_name = 'text';
return $variable_name;
}
} // END class
Each class should have a file of it's own.
No class is final without formatted comments.
Core framework PHP API
All functionality of the core platform is accessed through a single and consistent PHP-based API. No direct function calls should be made — instead data should be accessed and set through a secure and standard request / response model consistent with any HTTP GET/POST requests.
Request / response format
For developers looking to build custom functionality we've built a request/response process as the primary interface to the PHP framework. It mimics a REST-style API and standardizes calls and responses across the methods...so the PHP interaction will be nearly identical to future REST or verbose interactions.
Every request is made with a specific type and action, plus any required or optional parameters. It's response will contain an http-esque status code, a uid containing type/action/code, a human-readable status message, a more detailed contextual message, an echo of the request type and action, a payload with the full response data or false if the request failed, the api version, and a timestamp.
The PHP Request/Response looks like this:
<?php
$sample_request = new CASHRequest(
array(
'cash_request_type' => 'calendar',
'cash_action' => 'getevent',
'id' => 43
)
);
$sample_request->resonse:
{
"status_code":404, // http-style status code
"status_uid":"calendar_getevent_404", // uid of the response (request + status)
"status_message":"Not Found", // http-style status message
"contextual_message":"Event not found", // more specific error message
"request_type":"calendar", // echo of the request type
"action":"getevent", // echo of the request action
"payload":false, // contents of the response, or false if error
"api_version":2, // version number
"timestamp":1335416260 // request timestamp
}
?>
System requests
All actions defined for 'system' type requests:
system / addlogin
Adds a new user to the system, setting login details
@param {string} $address - the email address in question
@param {string} $password - the password
@return array|false
Parameters
address (REQUIRED)
password (REQUIRED)
is_admin (default: 0)
username (default: '')
display_name (default: 'Anonymous')
first_name (default: '')
last_name (default: '')
organization (default: '')
address_country (default: '')
force52compatibility (default: false)
data (default: '')
system / addlockcode
Creates a new lock/unlock code for and asset
@param {integer} $element_id - the element for which you're adding the lock code
@return string|false
Parameters
scope_table_alias (REQUIRED)
scope_table_id (REQUIRED)
user_id (default: 0)
system / deletesettings
Removes system settings of the given type for a user — be careful with wild cards. (Don't
use them unless you want to delete all system settings for a user. So, you know, don't.)
@return bool
Parameters
user_id (REQUIRED)
type (REQUIRED)
system / deletetemplate
Removes a user page/embed template
@return bool
Parameters
template_id (REQUIRED)
user_id (default: false)
system / getapicredentials
Gets API credentials for a user id
@param {int} $user_id - the user
@return array|false
Parameters
user_id (REQUIRED)
system / getlockcodes
Gets all lock codes for a given resource.
@return array|false
Parameters
scope_table_alias (REQUIRED)
scope_table_id (REQUIRED)
user_id (default: false)
system / getnewesttemplate
Gets the latest page/embed template for a given user.
@return string|false
Parameters
user_id (REQUIRED)
type (default: 'page')
all_details (default: false)
system / getsettings
Gets settings of the given type for a user. Set return_json to true and the system will
return the stored JSON without decoding.
@return string|array|false
Parameters
user_id (REQUIRED)
type (REQUIRED)
return_json (default: false)
system / gettemplate
Gets a user page/embed template for display.
@return string|false
Parameters
template_id (REQUIRED)
user_id (default: false)
all_details (default: false)
system / gettemplatesforuser
Gets all user page/embed template for display.
@return string|false
Parameters
user_id (REQUIRED)
type (default: false)
system / migratedb
Wrapper for CASHData migrateDB call. Currently used for SQLite -> MySQL migrations but any
from/to should be possible. More tests need to be written for full support.
@return bool
Parameters
todriver (REQUIRED)
tosettings (REQUIRED)
system / redeemlockcode
Attempts to redeem a given lock code, returning all details for the code on success or false
on failure. The code is tied to a scope_table_alias and scope_table_id pointing to a specific
asset, element, etc.
Pass a specific scope_table_alias, scope_table_id, or user_id to limit results to only matching
returns.
This will continue to return true for four hours after initial redemption — in the case of a
failed download this will give a user a second try without risking any long-term breach.
@return array|false
Parameters
code (REQUIRED)
scope_table_alias (default: false)
scope_table_id (default: false)
user_id (default: false)
system / setapicredentials
Sets or resets API credentials for a user
@param {int} $user_id - the user
@return array|false
Parameters
user_id (REQUIRED)
system / setlogincredentials
Resets email/password credentials for a user
@param {int} $user_id - the user
@return array|false
Parameters
user_id (REQUIRED)
address (default: false)
password (default: false)
username (default: false)
system / setresetflag
Sets or resets the password reset for a user
@return key(md5 hash)|false
Parameters
address (REQUIRED)
system / setsettings
Sets data for the given type for a user. This is basically a single key/value, so if the type
already exists this call with overwrite the existing value.
@return bool
Parameters
user_id (REQUIRED)
type (REQUIRED)
value (REQUIRED)
system / settemplate
Adds/edits a user page/embed template
@return bool
Parameters
user_id (REQUIRED)
type (default: false)
name (default: false)
template (default: false)
template_id (default: false)
system / validateapicredentials
Verifies API credentials and returns authorization type (api_key || api_fullauth || none) and user_id
@param {int} $user_id - the user
@return array|false
Parameters
api_key (REQUIRED)
api_secret (default: false)
system / validatelogin
Logins are validated using the email address given with a salted sha256 hash of the given
password. Blowfish is unavailable to PHP 5.2 (reliably) so we're limited in hashing. The
system salt is stored in /framework/settings/cashmusic.ini.php outside the database for
additional security.
In addition to the standard email/pass we also validate against Mozilla's Browser ID standard
using the browserid_assetion which can be passed in. This works with the CASHSystem Browser ID
calls to determine a positive login status for the user, get the email address, and compare it
to the system to return the correct user and login status.
Pass require_admin to only return true for admin-level users. Pass an element_id if you want
the login analytics to be tied to a specific element.
@return array|false
Parameters
address (REQUIRED)
password (REQUIRED)
require_admin (default: false)
verified_address (default: false)
browserid_assertion (default: false)
element_id (default: NULL)
keep_session (default: false)
system / validateresetflag
Verifies that the password reset is valid
@return bool
Parameters
address (REQUIRED)
key (REQUIRED)
Asset requests
All actions defined for 'asset' type requests:
asset / addasset
Parameters
title (REQUIRED)
description (REQUIRED)
user_id (REQUIRED)
location (default: '')
connection_id (default: 0)
hash (default: '')
size (default: 0)
public_url (default: '')
type (default: 'file')
tags (default: false)
metadata (default: false)
parent_id (default: 0)
public_status (default: 1)
asset / addlockcode
Wrapper for system lock code call
@param {integer} $element_id - the element for which you're adding the lock code
@return string|false
Parameters
asset_id (REQUIRED)
asset / claim
Reads asset details and redirects to the file directly. The success
Response is set here rather than in processRequest(), allowing it to
exist in the session
@param {integer} $id - the asset you are trying to retrieve
@return string
Parameters
id (REQUIRED)
element_id (default: 0)
asset / deleteasset
Parameters
id (REQUIRED)
user_id (default: false)
asset / editasset
Parameters
id (REQUIRED)
hash (default: false)
size (default: false)
location (default: false)
title (default: false)
description (default: false)
public_url (default: false)
connection_id (default: false)
type (default: false)
parent_id (default: false)
public_status (default: false)
user_id (default: false)
tags (default: false)
metadata (default: false)
asset / finalizeupload
Parameters
connection_id (REQUIRED)
filename (REQUIRED)
asset / findassets
Parameters
query (REQUIRED)
user_id (REQUIRED)
page (default: 1)
max_returned (default: 10)
asset / getanalytics
Pulls analytics queries in a few different formats
@return array
Parameters
analtyics_type (REQUIRED)
user_id (REQUIRED)
asset / getasset
Gets all details for a specific asset id (or array of ids) — pass in a single
id and get the asset details associative array, pass in an array of asset ids
and get an array of asset detail arrays.
@return void
Parameters
id (REQUIRED)
user_id (default: false)
asset / getassetsforconnection
Parameters
connection_id (REQUIRED)
asset / getassetsforparent
Parameters
parent_id (REQUIRED)
asset / getassetsforuser
Parameters
user_id (REQUIRED)
type (default: false)
parent_id (default: false)
asset / getasseturl
Parameters
connection_id (REQUIRED)
user_id (REQUIRED)
asset_location (REQUIRED)
params (default: false)
asset / getfulfillmentassets
Parameters
asset_details (REQUIRED)
type (default: 'fulfillment')
asset / getuploadparameters
Parameters
connection_id (REQUIRED)
user_id (REQUIRED)
asset / makepublic
Parameters
id (REQUIRED)
user_id (default: false)
asset / redeemcode
Wrapper for system lock code call
@param {string} $code - the code
@return bool
Parameters
code (REQUIRED)
user_id (default: false)
element_id (default: false)
asset / unlock
Adds an unlock state to platform session persistent store
@return boolean
Parameters
id (REQUIRED)
People requests
All actions defined for 'people' type requests:
people / addaddresstolist
Adds a user to a list. If no user exists for the email address passed, a
new user will be created then added to the list.
@param {string} $address - the email address in question
@param {int} $list_id - the id of the list
@param {bool} $verified - 0 for unverified, 1 to skip verification and mark ok
@param {string} $initial_comment - a comment passed with the list signup
@param {string} $additional_data - any extra data (JSON, etc) a dev might pass with signup for later use
@param {string} $name - if the user doesn't exist in the system this will be used as their display name
@return bool
Parameters
address (REQUIRED)
list_id (REQUIRED)
do_not_verify (default: false)
initial_comment (default: '')
additional_data (default: '')
name (default: 'Anonymous')
force_verification_url (default: false)
request_from_service (default: false)
service_opt_in (default: true)
extra_querystring (default: '')
first_name (default: '')
last_name (default: '')
people / addcontact
Adds a new contact to the system
@return id|false
Parameters
email_address (REQUIRED)
user_id (REQUIRED)
first_name (default: '')
last_name (default: '')
organization (default: '')
address_line1 (default: '')
address_line2 (default: '')
address_city (default: '')
address_region (default: '')
address_postalcode (default: '')
address_country (default: '')
phone (default: '')
notes (default: '')
links (default: '')
people / addmailing
Adds/edits a mailing
@return bool
Parameters
user_id (REQUIRED)
list_id (REQUIRED)
connection_id (REQUIRED)
subject (REQUIRED)
template_id (default: 0)
html_content (default: '')
text_content (default: '')
from_name (default: '')
people / addlist
Adds a new list to the system
@param {int} $list_id - the list
@param {int} $name - a name given to the list for easy recognition
@param {int} $description - a description, in case the name is terrible and offers no help
@param {int} $connection_id - a third party connection with which the list should sync
@return id|false
Parameters
name (REQUIRED)
user_id (REQUIRED)
description (default: '')
connection_id (default: 0)
people / checkverification
Returns true/false as to whether a user is verified for a specific list
@param {string} $address - the email address in question
@param {int} $list_id - the id of the list
@return bool
Parameters
address (REQUIRED)
list_id (REQUIRED)
people / deletelist
Removes an entire list and all member records. Use with caution.
@param {int} $list_id - the list
@return bool
Parameters
list_id (REQUIRED)
user_id (default: false)
people / editcontact
Parameters
id (REQUIRED)
email_address (default: false)
first_name (default: false)
last_name (default: false)
organization (default: false)
address_line1 (default: false)
address_line2 (default: false)
address_city (default: false)
address_region (default: false)
address_postalcode (default: false)
address_country (default: false)
phone (default: false)
notes (default: false)
links (default: false)
user_id (default: false)
people / editlist
Edits the details of a given list
@param {int} $list_id - the list
@param {int} $name - a name given to the list for easy recognition
@param {int} $description - a description, in case the name is terrible and offers no help
@param {int} $connection_id - a third party connection with which the list should sync
@return id|false
Parameters
list_id (REQUIRED)
name (default: false)
description (default: false)
connection_id (default: false)
user_id (default: false)
people / editmailing
Parameters
mailing_id (REQUIRED)
send_date (default: false)
subject (default: false)
html_content (default: false)
text_content (default: false)
user_id (default: false)
from_name (default: false)
people / getaddresslistinfo
Returns email address information for a specific list / address
@param {string} $address - the email address in question
@return array|false
Parameters
address (REQUIRED)
list_id (REQUIRED)
people / getanalytics
Pulls analytics queries in a few different formats
@return array
Parameters
analtyics_type (REQUIRED)
user_id (default: 0)
list_id (default: false)
people / getcontact
Parameters
id (REQUIRED)
user_id (default: false)
people / getcontactsbyinitials
Parameters
user_id (REQUIRED)
initial (REQUIRED)
people / getcontactinitials
Parameters
user_id (REQUIRED)
people / getlistsforuser
Returns all lists owned by a user
@param {int} $user_id - the user
@return array|false
Parameters
user_id (REQUIRED)
people / getlist
Returns basic information about a list
@param {int} $list_id - the id of the list
@return array|false
Parameters
list_id (REQUIRED)
user_id (default: false)
people / getmailing
Parameters
mailing_id (REQUIRED)
user_id (default: false)
people / getmailinganalytics
Parameters
mailing_id (REQUIRED)
user_id (default: false)
people / getuser
Gets details for an individual user
Parameters
user_id (REQUIRED)
people / getuseridforaddress
Returns user id for a given email address
@param {string} $address - the email address in question
@return id|false
Parameters
address (REQUIRED)
with_security_credentials (default: false)
people / getuseridforusername
Returns user id for a given username
@param {string} $address - the email address in question
@return id|false
Parameters
username (REQUIRED)
people / processwebhook
Used with the verbose API for remote webhook calls — incoming data into the system from
third parties, etc.
Parameters
origin (REQUIRED)
user_id (REQUIRED)
list_id (default: 0)
type (default: false)
data (default: false)
mandrill_events (default: false)
people / recordmailinganalytics
Parameters
mailing_id (REQUIRED)
sends (default: 0)
opens_total (default: 0)
opens_mobile (default: 0)
opens_country (default: false)
opens_id (default: false)
click_url (default: false)
failures (default: 0)
user_id (default: false)
people / removeaddress
Sets a user inactive for a given list. If the user is not present on the
list it returns true.
@param {string} $address - the email address in question
@param {int} $list_id - the id of the list
@return bool
Parameters
address (REQUIRED)
list_id (REQUIRED)
people / sendmailing
Parameters
mailing_id (REQUIRED)
user_id (default: false)
people / signintolist
Parameters
address (REQUIRED)
password (REQUIRED)
list_id (REQUIRED)
browserid_assertion (default: false)
element_id (default: NULL)
people / signup
Adds an email address to an existing list — optionally tie to a specific element for analytics
Parameters
list_id (REQUIRED)
address (REQUIRED)
user_id (default: false)
comment (default: '')
name (default: 'Anonymous')
element_id (default: false)
first_name (default: '')
last_name (default: '')
additional_data (default: '')
people / verifyaddress
Parameters
address (REQUIRED)
list_id (REQUIRED)
verification_code (REQUIRED)
people / viewlist
Parameters
list_id (REQUIRED)
unlimited (default: false)
user_id (default: false)
Commerce requests
All actions defined for 'commerce' type requests:
commerce / additem
Parameters
user_id (REQUIRED)
name (REQUIRED)
description (default: '')
sku (default: '')
price (default: 0)
flexible_price (default: 0)
available_units (default: -1)
digital_fulfillment (default: 0)
physical_fulfillment (default: 0)
physical_weight (default: 0)
physical_width (default: 0)
physical_height (default: 0)
physical_depth (default: 0)
variable_pricing (default: 0)
fulfillment_asset (default: 0)
descriptive_asset (default: 0)
commerce / addorder
Parameters
user_id (REQUIRED)
order_contents (REQUIRED)
transaction_id (default: -1)
physical (default: 0)
digital (default: 0)
cash_session_id (default: '')
element_id (default: 0)
customer_user_id (default: 0)
fulfilled (default: 0)
canceled (default: 0)
notes (default: '')
country_code (default: '')
currency (default: 'USD')
commerce / addtransaction
Parameters
user_id (REQUIRED)
connection_id (REQUIRED)
connection_type (REQUIRED)
service_timestamp (default: '')
service_transaction_id (default: '')
data_sent (default: '')
data_returned (default: '')
successful (default: -1)
gross_price (default: 0)
service_fee (default: 0)
status (default: 'abandoned')
currency (default: 'USD')
commerce / deleteitem
Parameters
id (REQUIRED)
user_id (default: false)
commerce / edititem
Parameters
id (REQUIRED)
name (default: false)
description (default: false)
sku (default: false)
price (default: false)
flexible_price (default: false)
available_units (default: false)
digital_fulfillment (default: false)
physical_fulfillment (default: false)
physical_weight (default: false)
physical_width (default: false)
physical_height (default: false)
physical_depth (default: false)
variable_pricing (default: false)
fulfillment_asset (default: false)
descriptive_asset (default: false)
user_id (default: false)
commerce / editorder
Parameters
id (REQUIRED)
fulfilled (default: false)
canceled (default: false)
notes (default: false)
country_code (default: false)
customer_user_id (default: false)
order_contents (default: false)
transaction_id (default: false)
physical (default: false)
digital (default: false)
user_id (default: false)
commerce / edittransaction
Parameters
id (REQUIRED)
service_timestamp (default: false)
service_transaction_id (default: false)
data_sent (default: false)
data_returned (default: false)
successful (default: false)
gross_price (default: false)
service_fee (default: false)
status (default: false)
commerce / getanalytics
Pulls analytics queries in a few different formats
@return array
Parameters
analtyics_type (REQUIRED)
user_id (REQUIRED)
date_low (default: false)
date_high (default: false)
commerce / getitem
Parameters
id (REQUIRED)
user_id (default: false)
commerce / getitemsforuser
Parameters
user_id (REQUIRED)
commerce / getorder
Parameters
id (REQUIRED)
deep (default: false)
user_id (default: false)
commerce / getordersforuser
Parameters
user_id (REQUIRED)
include_abandoned (default: false)
max_returned (default: false)
commerce / gettransaction
Parameters
id (REQUIRED)
user_id (default: false)
commerce / finalizepayment
Parameters
order_id (REQUIRED)
creation_date (REQUIRED)
direct_post_details (default: false)
commerce / initiatecheckout
Parameters
user_id (REQUIRED)
connection_id (REQUIRED)
order_contents (default: false)
item_id (default: false)
element_id (default: false)
total_price (default: false)
return_url_only (default: false)
Calendar requests
All actions defined for 'calendar' type requests:
calendar / addevent
Parameters
date (REQUIRED)
user_id (REQUIRED)
venue_id (REQUIRED)
purchase_url (default: '')
comment (default: '')
published (default: 0)
cancelled (default: 0)
calendar / addvenue
Parameters
name (REQUIRED)
city (REQUIRED)
address1 (default: '')
address2 (default: '')
region (default: '')
country (default: '')
postalcode (default: '')
url (default: '')
phone (default: '')
calendar / deletevenue
Parameters
venue_id (REQUIRED)
calendar / editevent
Parameters
event_id (REQUIRED)
date (default: false)
venue_id (default: false)
purchase_url (default: false)
comment (default: false)
published (default: false)
cancelled (default: false)
user_id (default: false)
calendar / editvenue
Parameters
venue_id (REQUIRED)
name (default: false)
address1 (default: false)
address2 (default: false)
city (default: false)
region (default: false)
country (default: false)
postalcode (default: false)
url (default: false)
phone (default: false)
calendar / findvenues
Parameters
query (REQUIRED)
page (default: 1)
max_returned (default: 12)
calendar / getallvenues
Parameters
calendar / geteventsbetween
Parameters
user_id (REQUIRED)
offset (default: 0)
cutoff_date_low (default: 'now')
cancelled_status (default: 0)
published_status (default: 1)
cutoff_date_high (default: 2051244000)
calendar / getevent
Parameters
event_id (REQUIRED)
calendar / getevents
Parameters
user_id (REQUIRED)
visible_event_types (REQUIRED)
offset (default: 0)
published_status (default: 1)
cancelled_status (default: 0)
calendar / getvenue
Parameters
venue_id (REQUIRED)
Element requests
All actions defined for 'element' type requests:
element / addelement
Parameters
name (REQUIRED)
type (REQUIRED)
options_data (REQUIRED)
user_id (REQUIRED)
element / addlockcode
Wrapper for system lock code call
@param {integer} $element_id - the element for which you're adding the lock code
@return string|false
Parameters
element_id (REQUIRED)
element / deleteelement
Parameters
id (REQUIRED)
user_id (default: false)
element / editelement
Parameters
id (REQUIRED)
name (REQUIRED)
options_data (REQUIRED)
user_id (default: false)
element / getanalytics
Pulls analytics queries in a few different formats
@return array
Parameters
analtyics_type (REQUIRED)
user_id (REQUIRED)
element_id (default: 0)
element / getelement
Parameters
id (REQUIRED)
element / getelementsforuser
Parameters
user_id (REQUIRED)
element / getelementtemplate
Parameters
element_id (REQUIRED)
return_template (default: false)
element / getmarkup
Parameters
id (REQUIRED)
status_uid (REQUIRED)
original_request (default: false)
original_response (default: false)
access_method (default: 'direct')
location (default: false)
element / getsupportedtypes
Parameters
element / redeemcode
Wrapper for system lock code call
@param {string} $code - the code
@param {integer} $element_id - the element for which you're adding the lock code
@return bool
Parameters
code (REQUIRED)
element_id (REQUIRED)
element / setelementtemplate
Parameters
element_id (REQUIRED)
template_id (REQUIRED)
user_id (default: false)
Elements
Elements are like a plugin, or functional bundle, for the CASH platform. Each one is a standalone package containing descriptive metadata, a controller class, view templates, and forms to plug into the admin app. Specifically, each element consists of:
- A main controller class file
- A support directory containing:
- templates directory for mustache template views for every state (plus admin)
- admin.php as a controller for the amdin template
- image.jpg as a header/descriptive image
- metadata.json containing a version number, friendly name, description, etc
Data for each instance of an element is stored as a JSON string in the database, so the data itself can be pretty flexible for each element type.
The public-facing code in the element is designed to respond to targeted POST and/or GET requests — so a CASH Request is made and the element responds to the CASH Response if the correct element_id was set along with the request. So an element is embedded with a single function call, and will respond automatically when interacted with. The whole idea being that it's a simple to use structure that can be powerful and flexible enough to innovate on top of the PHP API.
As a starting point, look at the StaticContent element.
Admin app
The admin app for the platform (/interfaces/php/admin) is a fairly straight-forward MVC-style webapp built with a front controller, individual controllers for each route, mustache views, and using the framework for the model instead of a traditional database layer. Basically it's dog-fooding the PHP API but building a much more complex app than a simple element.
Like the framework, the admin app is built with minimal requirements, not using any more robust PHP app frameworks. The reason for this decision was the distributed version of the platform — what we lose in functionality we gain in portability, which is a major concern.
In terms of structure, it's fairly simple:
- At the root there's an .htaccess redirect pointing all incoming traffic at controller.php, which pulls in settings from constants.php
- A page is rendered based on pieces found in the /components directory
- Each page/route has a controller in /components/pages/controllers and the controller calls a mustache template from /components/pages/templates
- We're in the process of moving localized text to the /components/text directory, and similarly menus are pulled out by language in the /components/menu directory
- Two simple helper classes are found in the /classes directory
- The main page UI is a simple mustache-based template found in /ui/default — there's not currently a setting in the admin to allow theming but it's essentially just a path change away
Currently the admin is more of a code-wrapper than an application with elegant UI/UX. Our prime focus is improving that, making each section of the admin feel intuitive and easy as well as adding more help infrastructure.
It shouldn't be lost that the admin app is structured to mirror the Request/Response types — this is very much on purpose with the goal of getting musicians and developers speaking the same language.
Also, Jackson.