# File Structure

Hyperstack adds the following files and directories to your Rails application:

```
/app/hyperstack
/app/operations
/app/policies
/config/initializers/hyperstack.rb
/app/javascript/packs/client_and_server.js
/app/javascript/packs/client_only.js
```

In addition there are configuration settings in existing Rails files that are explained in the next section. Below we cover the purpose of each these files, and their contents.

## The `/app/hyperstack/` Directory

Here lives all your Hyperstack code that will run on the client. Some of the subdirectories are *isomorphic* meaning the code is shared between the client and the server, other directories are client only.

Within the `hyperstack` directory there can be the following sub-directories:

* `components` *(client-only)* is where your components live.

  > Following Rails conventions a component with a class of `Bar::None::FooManchu` should be in a file named `components/bar/none/foo_manchu.rb`
* `models` *(isomorphic)* is where ActiveRecord models are shared with the client. More on this below.
* `operations` *(isomorphic)* is where Hyperstack Operations will live.
* `shared` *(isomorphic)* is where you can put shared code that are not models or operations.
* Any other subdirectory (such as `libs` and `client-ops`) will be considered client-only.

## Sharing Models and Operations

Files in the `hyperstack` `/models` and `/operations` directories are loaded on the client *and* the server. So when you place a model's class definition in the `hyperstack/models` directory the class is available on the client.

Assuming:

```ruby
# app/hyperstack/models/todo.rb
class Todo < ApplicationRecord
  ...
end
```

Then

```
  Todo.count # will return the same value on the client and the server
```

> See the Policy section below for how access to the actual data is controlled. Remember a Model *describes* some data, but the actual data is stored in the database, and protected by Policies.

Likewise Operations placed in the `/operations` directory can be run on the client or the server, or in the case of a `ServerOp` the operation can be invoked on the client, but will run on the server.

Hyperstack sets things up so that Rails will first look in the `hyperstack` `/models` and `/operations` directories, and then in the server only `app/models` and `app/operations` directories. So if you don't want some model shared you can just leave it in the normal `app` directory.

## Splitting Class Definitions

There are cases where you would like split a class definition into its shared and server-only aspects. For example there may be code in a model that cannot be sensibly run on the client. Hyperstack augments the Rails dependency lookup mechanism so that when a file is found in a `hyperstack` directory we will *also* load any matching file in the normal `app` directory.

This works because Ruby classes are *open*, so that you can define a class (or module) in multiple places.

## Server Side Operations

Operations are Hyperstack's way of providing *Service Objects*: classes that perform some operation not strictly belonging to a single model, and often involving other services such as remote APIs. *The idea of Operations comes from the* [*Trailblazer Framework.*](https://trailblazer.to/2.0/gems/operation/2.0/index.html)

As such Operations can be useful strictly on the server side, and so can be added to the `app/operations` directory.

Server side operations can also be remotely run from the client. Such operations are defined as subclasses of `Hyperstack::ServerOp`.

The right way to define a `ServerOp` is to place its basic definition including its parameter signature in the `hyperstack/operations` directory, and then placing the rest of the operation's definition in the `app/operations` directory.

## Policies

Hyperstack uses Policies to define access rights to your models. Policies are placed in the `app/policies` directory. For example the policies for the `Todo` model would defined by the `TodoPolicy` class located at `app/policies/todo_policy.rb` Details on policies can be found [Policy section of this document.](https://docs.hyperstack.org/isomorphic-dsl/hyper-policy).

## Example Directory Structure

```
└── app/
    ├── models/
    │   └── user.rb # private section of User model
    ├── operations/
    │   └── email_the_owner.rb # server code
    ├── hyperstack/
    │   ├── components/
    │   │   ├── app.rb
    │   │   ├── edit_todo.rb
    │   │   ├── footer.rb
    │   │   ├── header.rb
    │   │   ├── show_todo.rb
    │   │   └── todo_index.rb
    │   ├── models/
    │   │   ├── application_record.rb # usually no need to split this
    │   │   ├── todo.rb # note all of Todo definition is public
    │   │   └── user.rb # user has a public and private section
    │   └── operations/
    │       └── email_the_owner.rb # serverop interface only
    └── policies/
        ├── todo_policy.rb
        └── user_policy.rb
```

These directories are where most of your work will be done during Hyperstack development.

> ### What about Controllers and Views?
>
> Hyperstack works alongside Rails controllers and views. In a clean-sheet Hyperstack app you never need to create a controller or a view. On the other hand if you have existing code or aspects of your project that you feel would work better using a traditional MVC approach everything will work fine. You can also merge the two worlds: Hyperstack includes two helpers that allow you to mount components either from a controller or from within a view.

## The Hyperstack Initializer

The Hyperstack configuration can be controlled via the `config/initializers/hyperstack.rb` initializer file. Using the installer will set up a reasonable set of of options, which you can tweak as needed.

Here is a summary of the various configuration settings:

```ruby
# config/initializers/hyperstack.rb

# server_side_auto_require will patch the ActiveSupport Dependencies module
# so that you can define classes and modules with files in both the
# app/hyperstack/xxx and app/xxx directories.  

require "hyperstack/server_side_auto_require.rb"

# By default the generators will generate new components as subclasses of
# HyperComponent.  You can change this using the component_base_class setting.

Hyperstack.component_base_class = 'HyperComponent' # i.e. 'ApplicationComponent'

# prerendering is default :off, you should wait until your
# application is relatively well debugged before turning on.

Hyperstack.prerendering = :off # or :on

# The transport setting controls how push (websocket) communications are
# implemented.  The default is :none, but will be set to :action_cable if you
# install hyper-model.

# Other possibilities are :action_cable, :pusher (see www.pusher.com)
# or :simple_poller which is sometimes handy during system debug.

Hyperstack.transport = :action_cable # :pusher, :simple_poller or :none

# hotloader settings:
# sets the port hotloader will listen on.  Note this must match the value used
# to start the hotloader typically in the foreman Procfile.
Hyperstack.hotloader_port = 25222
# seconds between pings over the hotloader websocket.  Normally not needed.
Hyperstack.hotloader_ping = nil
# hotloader will automatically reload callbacks when effected classes are
# reloaded.  Not recommended to change this.
Hyperstack.hotloader_ignore_callback_mapping = false

# Transport settings
# seconds before timeout when sending messages between the rails console and  
# the server.
Hyperstack.send_to_server_timeout = 10

# Transport specific options
Hyperstack.opts, {
  # pusher specific options
  app_id: 'your pusher app id',
  key: 'your pusher key',
  secret: 'your pusher secret',
  cluster: 'mt1', # pusher cluster defaults to mt1
  encrypted: true, # encrypt pusher comms, defaults to true
  refresh_channels_every: 2.minutes, # how often to check which channels are alive

  # simple poller specific options
  expire_polled_connection_in: 5.minutes, # when to kill simple poller connections
  seconds_between_poll: 5.seconds, # how fast to poll when using simple poller
  expire_new_connection_in: 10.seconds, # how long to keep initial sessions alive
}

# Namespace used to keep hyperstack communication separate from other websockets
Hyperstack.channel_prefix = 'synchromesh'

# If there a JS console available should websocket comms be logged?
Hyperstack.client_logging = true

# Automatically create a (possibly temporary) websocket connection as each
# browser session starts.  Usually this is needed for further authentication and
# should be left as true
Hyperstack.connect_session =  true

# Where to store the connection tables.  Default is :active_record but you
# can also specify redis.  If specifying redis the redis url defaults to
# redis://127.0.0.1:6379
Hyperstack.connection = [adapter: :active_record] # or
                      # [adapter: :redis, redis_url: 'redis://127.0.0.1:6379]

# The import directive loads optional portions of the various hyperstack gems.
# Here are the common imports typically included:

Hyperstack.import 'hyperstack/hotloader', client_only: true if Rails.env.development?

# and these are typically not imported:

# React source is normally brought in through webpacker
# Hyperstack.import 'react/react-source-browser'

# add this line if you need jQuery AND ARE NOT USING WEBPACK
# Hyperstack.import 'hyperstack/component/jquery', client_only: true

# The following are less common settings which you should never have to change:
Hyperstack.prerendering_files = ['hyperstack-prerender-loader.js']
Hyperstack.public_model_directories = ['app/hyperstack/models']


# change definition of on_error to control how errors such as validation
# exceptions are reported on the server
module Hyperstack
  def self.on_error(operation, err, params, formatted_error_message)
    ::Rails.logger.debug(
      "#{formatted_error_message}\n\n" +
      Pastel.new.red(
        'To further investigate you may want to add a debugging '\
        'breakpoint to the on_error method in config/initializers/hyperstack.rb'
      )
    )
  end
end if Rails.env.development?
```

## Hyperstack Packs

Rails `webpacker` organizes javascript into *packs*. Hyperstack will look for and load one of two packs depending on if you are prerendering or not.

The default content of these packs are as follows:

```javascript
//app/javascript/packs/client_and_server.js
// these packages will be loaded both during prerendering and on the client
React = require('react');                         // react-js library
createReactClass = require('create-react-class'); // backwards compatibility with ECMA5
History = require('history');                     // react-router history library
ReactRouter = require('react-router');            // react-router js library
ReactRouterDOM = require('react-router-dom');     // react-router DOM interface
ReactRailsUJS = require('react_ujs');             // interface to react-rails
// to add additional NPM packages run `yarn add package-name@version`
// then add the require here.
```

```javascript
//app/javascript/packs/client_only.js
// add any requires for packages that will run client side only
ReactDOM = require('react-dom');               // react-js client side code
jQuery = require('jquery');                    // remove if you don't need jQuery
// to add additional NPM packages call run yarn add package-name@version
// then add the require here.
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.hyperstack.org/rails-installation/file-structure.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
