Stage 1
This commit is contained in:
21
src/config/sys.config
Normal file
21
src/config/sys.config
Normal file
@@ -0,0 +1,21 @@
|
||||
[
|
||||
{eventhub, [
|
||||
{http_port, 8080},
|
||||
{ws_port, 8081},
|
||||
{admin_http_port, 8445},
|
||||
{admin_ws_port, 8446},
|
||||
{jwt_secret, <<"change_me_in_production">>},
|
||||
{argon2_params, #{t_cost => 2, m_cost => 19, parallelism => 1}}
|
||||
]},
|
||||
{mnesia, [
|
||||
{dir, "Mnesia.${NODE}"}
|
||||
]},
|
||||
{kernel, [
|
||||
{logger_level, info},
|
||||
{logger, [
|
||||
{handler, default, logger_std_h,
|
||||
#{formatter => {logger_formatter, #{template => [time, " ", level, ": ", msg, "\n"]}}}
|
||||
}
|
||||
]}
|
||||
]}
|
||||
].
|
||||
23
src/eventhub.app.src
Normal file
23
src/eventhub.app.src
Normal file
@@ -0,0 +1,23 @@
|
||||
{application, eventhub, [
|
||||
{description, "Event Management Platform"},
|
||||
{vsn, "0.0.1"},
|
||||
{registered, []},
|
||||
{mod, {eventhub_app, []}},
|
||||
{applications, [
|
||||
kernel,
|
||||
stdlib,
|
||||
mnesia,
|
||||
crypto,
|
||||
cowboy,
|
||||
jsx
|
||||
]},
|
||||
{env, [
|
||||
{http_port, 8080},
|
||||
{ws_port, 8081},
|
||||
{admin_http_port, 8445},
|
||||
{admin_ws_port, 8446}
|
||||
]},
|
||||
{modules, []},
|
||||
{licenses, ["Apache-2.0"]},
|
||||
{links, []}
|
||||
]}.
|
||||
24
src/eventhub_app.erl
Normal file
24
src/eventhub_app.erl
Normal file
@@ -0,0 +1,24 @@
|
||||
%% Основной модуль приложения
|
||||
-module(eventhub_app).
|
||||
-behaviour(application).
|
||||
|
||||
-export([start/2, stop/1]).
|
||||
|
||||
start(_StartType, _StartArgs) ->
|
||||
% Запускаем Mnesia
|
||||
application:ensure_all_started(mnesia),
|
||||
|
||||
case infra_sup:start_link() of
|
||||
{ok, Pid} ->
|
||||
% Инициализируем таблицы и ждем готовности
|
||||
ok = infra_mnesia:init_tables(),
|
||||
ok = infra_mnesia:wait_for_tables(),
|
||||
|
||||
% Здесь позже запустим HTTP-сервер и другие сервисы
|
||||
{ok, Pid};
|
||||
Error ->
|
||||
Error
|
||||
end.
|
||||
|
||||
stop(_State) ->
|
||||
ok.
|
||||
6
src/handlers/handler_health.erl
Normal file
6
src/handlers/handler_health.erl
Normal file
@@ -0,0 +1,6 @@
|
||||
-module(handler_health).
|
||||
-export([init/2]).
|
||||
|
||||
init(Req, _Opts) ->
|
||||
{ok, Resp} = cowboy_req:reply(200, #{<<"content-type">> => <<"application/json">>}, <<"{\"status\":\"ok\"}">>, Req),
|
||||
Resp.
|
||||
135
src/infra/infra_mnesia.erl
Normal file
135
src/infra/infra_mnesia.erl
Normal file
@@ -0,0 +1,135 @@
|
||||
-module(infra_mnesia).
|
||||
-behaviour(gen_server).
|
||||
|
||||
-include("records.hrl").
|
||||
|
||||
%% API
|
||||
-export([start_link/0, init_tables/0, wait_for_tables/0]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
|
||||
|
||||
-define(TABLES, [
|
||||
user, session, calendar, calendar_share, event, recurrence_exception,
|
||||
booking, review, report, banned_word, ticket, subscription, audit_log
|
||||
]).
|
||||
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||
|
||||
init_tables() ->
|
||||
gen_server:call(?MODULE, init_tables).
|
||||
|
||||
wait_for_tables() ->
|
||||
gen_server:call(?MODULE, wait_for_tables).
|
||||
|
||||
init([]) ->
|
||||
{ok, #{}}.
|
||||
|
||||
handle_call(init_tables, _From, State) ->
|
||||
ok = ensure_schema(),
|
||||
lists:foreach(fun create_table/1, ?TABLES),
|
||||
{reply, ok, State};
|
||||
handle_call(wait_for_tables, _From, State) ->
|
||||
mnesia:wait_for_tables(?TABLES, 5000),
|
||||
{reply, ok, State}.
|
||||
|
||||
handle_cast(_Msg, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
handle_info(_Info, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, _State) ->
|
||||
ok.
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%% Internal functions
|
||||
ensure_schema() ->
|
||||
case mnesia:create_schema([node()]) of
|
||||
ok ->
|
||||
ok;
|
||||
{error, {Node, {already_exists, Node}}} ->
|
||||
ok;
|
||||
{error, {already_exists, _Node}} ->
|
||||
ok;
|
||||
{error, Reason} ->
|
||||
error({schema_creation_failed, Reason})
|
||||
end.
|
||||
|
||||
create_table(Table) ->
|
||||
case mnesia:create_table(Table, table_opts(Table)) of
|
||||
{atomic, ok} ->
|
||||
ok;
|
||||
{aborted, {already_exists, _}} ->
|
||||
ok;
|
||||
{aborted, Reason} ->
|
||||
error({table_creation_failed, Table, Reason})
|
||||
end.
|
||||
|
||||
%% Опции таблиц без индексов (добавим позже)
|
||||
table_opts(user) ->
|
||||
[
|
||||
{attributes, record_info(fields, user)},
|
||||
{ram_copies, [node()]}
|
||||
];
|
||||
table_opts(session) ->
|
||||
[
|
||||
{attributes, record_info(fields, session)},
|
||||
{ram_copies, [node()]}
|
||||
];
|
||||
table_opts(calendar) ->
|
||||
[
|
||||
{attributes, record_info(fields, calendar)},
|
||||
{ram_copies, [node()]}
|
||||
];
|
||||
table_opts(calendar_share) ->
|
||||
[
|
||||
{attributes, record_info(fields, calendar_share)},
|
||||
{ram_copies, [node()]}
|
||||
];
|
||||
table_opts(event) ->
|
||||
[
|
||||
{attributes, record_info(fields, event)},
|
||||
{ram_copies, [node()]}
|
||||
];
|
||||
table_opts(recurrence_exception) ->
|
||||
[
|
||||
{attributes, record_info(fields, recurrence_exception)},
|
||||
{ram_copies, [node()]}
|
||||
];
|
||||
table_opts(booking) ->
|
||||
[
|
||||
{attributes, record_info(fields, booking)},
|
||||
{ram_copies, [node()]}
|
||||
];
|
||||
table_opts(review) ->
|
||||
[
|
||||
{attributes, record_info(fields, review)},
|
||||
{ram_copies, [node()]}
|
||||
];
|
||||
table_opts(report) ->
|
||||
[
|
||||
{attributes, record_info(fields, report)},
|
||||
{ram_copies, [node()]}
|
||||
];
|
||||
table_opts(banned_word) ->
|
||||
[
|
||||
{attributes, record_info(fields, banned_word)},
|
||||
{ram_copies, [node()]}
|
||||
];
|
||||
table_opts(ticket) ->
|
||||
[
|
||||
{attributes, record_info(fields, ticket)},
|
||||
{ram_copies, [node()]}
|
||||
];
|
||||
table_opts(subscription) ->
|
||||
[
|
||||
{attributes, record_info(fields, subscription)},
|
||||
{ram_copies, [node()]}
|
||||
];
|
||||
table_opts(audit_log) ->
|
||||
[
|
||||
{attributes, record_info(fields, audit_log)},
|
||||
{ram_copies, [node()]}
|
||||
].
|
||||
28
src/infra/infra_sup.erl
Normal file
28
src/infra/infra_sup.erl
Normal file
@@ -0,0 +1,28 @@
|
||||
%% Супервизор верхнего уровня
|
||||
-module(infra_sup).
|
||||
-behaviour(supervisor).
|
||||
|
||||
-export([start_link/0]).
|
||||
-export([init/1]).
|
||||
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
init([]) ->
|
||||
SupFlags = #{strategy => one_for_one, intensity => 5, period => 10},
|
||||
|
||||
Mnesia = #{
|
||||
id => infra_mnesia,
|
||||
start => {infra_mnesia, start_link, []},
|
||||
restart => permanent,
|
||||
shutdown => 5000,
|
||||
type => worker,
|
||||
modules => [infra_mnesia]
|
||||
},
|
||||
|
||||
% Временная заглушка для HTTP-сервера (будет добавлен позже)
|
||||
% Cowboy = #{...}
|
||||
|
||||
ChildSpecs = [Mnesia],
|
||||
|
||||
{ok, {SupFlags, ChildSpecs}}.
|
||||
Reference in New Issue
Block a user