feat: Initial MVP with home server identity model

- User model with Ed25519 keypair identity
- Register/login on home server (creates keypair)
- Join guest servers with signature verification
- Public endpoints for cross-server identity
- Channel and message CRUD
- JWT authentication middleware

Architecture: Home server model, no federation, client-driven sync
This commit is contained in:
Z User committed 2026-02-19 23:29:52 +00:00
commit 6a8977c4c3
14 files changed
+1494

No files matched your search

+82
View File
@@ -0,0 +1,82 @@
import 'package:chat_server/models.dart';
import 'package:chat_server/objectbox.g.dart';
import 'package:relic/relic.dart';
import '../utils/extensions.dart';
/// Get all channels
Future<Response> getChannelsHandler(Request req) async {
final channels = channelBox.getAll();
return Response.ok(
body: {
'channels': channels
.map((c) => {
'id': c.id,
'name': c.name,
'description': c.description,
'createdAt': c.createdAt.toIso8601String(),
})
.toList(),
}.toBody,
);
}
/// Create a channel (requires 'admin' role)
Future<Response> createChannelHandler(Request req) async {
final body = await req.asJson();
final name = (body['name'] as String?)?.trim().toLowerCase().replaceAll(' ', '-');
final description = body['description'] as String?;
if (name == null || name.isEmpty) {
return Response.badRequest(
body: Body.fromString('Channel name required'),
);
}
// Check if channel exists
final existing = channelBox.query(Channel_.name.equals(name)).build().findFirst();
if (existing != null) {
return Response.badRequest(
body: Body.fromString('Channel already exists'),
);
}
final channel = Channel(name: name, description: description);
final id = channelBox.put(channel);
return Response.ok(
body: {
'id': id,
'name': name,
'description': description,
'createdAt': channel.createdAt.toIso8601String(),
}.toBody,
);
}
/// Get channel by ID
Future<Response> getChannelHandler(Request req, String channelIdStr) async {
final channelId = int.tryParse(channelIdStr);
if (channelId == null) {
return Response.badRequest(
body: Body.fromString('Invalid channel ID'),
);
}
final channel = channelBox.get(channelId);
if (channel == null) {
return Response.notFound(
body: Body.fromString('Channel not found'),
);
}
return Response.ok(
body: {
'id': channel.id,
'name': channel.name,
'description': channel.description,
'createdAt': channel.createdAt.toIso8601String(),
}.toBody,
);
}