diff --git a/Module/ModLogs/Entry.cs b/Module/ModLogs/Entry.cs
new file mode 100644
index 0000000..c3bec89
--- /dev/null
+++ b/Module/ModLogs/Entry.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Noikoio.RegexBot.Module.ModLogs
+{
+ ///
+ /// Represents a log entry.
+ ///
+ class Entry
+ {
+ readonly int _logId;
+ readonly DateTime _ts;
+ readonly ulong? _invokeId;
+ readonly ulong _targetId;
+ readonly ulong? _channelId;
+ readonly string _type;
+ readonly string _message;
+
+ ///
+ /// Gets the ID value of this log entry.
+ ///
+ public int Id => _logId;
+ ///
+ /// Gets the timestamp (a with ) of the entry.
+ ///
+ public DateTime Timestamp => _ts;
+ ///
+ /// Gets the ID of the invoking user.
+ /// This value exists only if this entry was created through action of another user that is not the target.
+ ///
+ public ulong? Invoker => _invokeId;
+ ///
+ /// Gets the ID of the user to which this log entry corresponds.
+ ///
+ public ulong Target => _targetId;
+ ///
+ /// Gets the guild channel ID to which this log entry corresponds, if any.
+ ///
+ public ulong? TargetChannel => _channelId;
+ ///
+ /// Gets this log entry's 'type', or category.
+ ///
+ public string LogType => _type;
+ ///
+ /// Gets the content of this log entry.
+ ///
+ public string Message => _message;
+
+ public Entry()
+ {
+ throw new NotImplementedException();
+ }
+
+ // TODO figure out some helper methods to retrieve data of other entities by ID, if it becomes necessary
+ }
+}
diff --git a/Module/ModLogs/EventListener.cs b/Module/ModLogs/EventListener.cs
new file mode 100644
index 0000000..3984696
--- /dev/null
+++ b/Module/ModLogs/EventListener.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Noikoio.RegexBot.Module.ModLogs
+{
+ ///
+ /// Listens for certain events and places them on the log.
+ ///
+ class EventListener
+ {
+ }
+}
diff --git a/Module/ModLogs/MessageCache.cs b/Module/ModLogs/MessageCache.cs
new file mode 100644
index 0000000..80cd933
--- /dev/null
+++ b/Module/ModLogs/MessageCache.cs
@@ -0,0 +1,110 @@
+using Discord.WebSocket;
+using Newtonsoft.Json.Linq;
+using Noikoio.RegexBot.ConfigItem;
+using Npgsql;
+using NpgsqlTypes;
+using System.Threading.Tasks;
+
+namespace Noikoio.RegexBot.Module.DBCache
+{
+ ///
+ /// Caches information regarding all incoming messages.
+ /// The function of this feature should be transparent to the user, and thus no configuration is needed.
+ ///
+ class MessageCache : BotFeature
+ {
+ // TODO Something that clears expired cache items
+ private readonly DatabaseConfig _db;
+
+ public override string Name => nameof(MessageCache);
+
+ public MessageCache(DiscordSocketClient client) : base(client)
+ {
+ _db = RegexBot.Config.Database;
+
+ if (_db.Enabled)
+ {
+ CreateCacheTables();
+
+ client.MessageReceived += Client_MessageReceived;
+ //client.MessageUpdated += Client_MessageUpdated;
+ }
+ else
+ {
+ Log("No database storage available.").Wait();
+ }
+ }
+
+ #region Table setup
+ const string TableMessage = "cache_messages";
+
+ public override Task