#Welcome
ATDT is a complete bulletin board system that runs on ordinary shared web hosting. Callers get an authentic CP437 terminal in the browser: ANSI art, hotkey menus, message bases, live chat, and door games. You get a modern web console to run all of it.
Everything lives in one folder. The board is the atdt/ directory you uploaded;
all of its data (database, configuration, custom themes, door saves) lives in
data/ inside it. There is no daemon, no build step, and nothing to install on the
server beyond PHP itself.
Vocabulary
| Caller | A user of the board, connected through the terminal page. |
| SysOp | You. System operator: level 255, console access. |
| Node | One live connection. Two browser tabs are two nodes. |
| The matrix | The pre-login screen where callers log in or apply. |
| Area | One message base: a board within the board. |
| Category | A named shelf that groups areas in the area list. |
| Door | A game or utility that runs inside the board. |
| ACS | Access Control String: who may see or do a thing. |
| Pipe codes | Inline color codes like |12 that color text. |
| Scope | A menu's own current message area, separate from the board's. Menus that declare the same scope name share one; menus that declare none use the board's current area, as ever. New in 1.6.5. |
| Console | The web admin at /admin/. Callers never see it. |
#Installing the board
Requirements
The installer checks all of this on its first screen and explains anything missing. On a too-old PHP it shows a friendly page instead of an error.
The install wizard
- Upload the contents of the
atdt/folder to your web space. The web root and a subdirectory (for example/bbs/) both work. - Visit
https://your-site.example/install.php. The environment check runs; continue. - Pick the database. SQLite needs nothing and is right for almost everyone; the database file
gets a randomized name inside
data/. MySQL asks for host, port, database name, user and password, with a test-connection button. - Board identity: board name (up to 60 characters), SysOp handle (3 to 20 characters: letters, digits, space, period, underscore, hyphen), SysOp password (minimum 8 characters, typed twice), board timezone (US zones listed first; this is the clock callers see and the boundary for the daily tick), and base URL (auto-detected; correct it if your board's public address differs).
- Done. The installer prints your cron line (chapter 17) and links to the board and the console.
install.php if you like, but you do
not have to. It locks itself and refuses to run while data/config.php
exists.Reinstalling
To wipe and start over, delete data/config.php (or the whole data/
folder) and visit install.php again. To upgrade in place instead, see
chapter 19.
#Your first hour as SysOp
The console lives at /admin/. Log in with the SysOp handle and password from the
wizard. Only level 255 accounts may enter; wrong passwords are throttled (five tries per 15
minutes, lockouts logged); every session rides a CSRF-protected cookie.
A sensible first hour:
- Open the board in another tab and look around as a caller. The seeded board has two areas on a "Main Boards" shelf, a welcome bulletin, and two doors.
- Settings: confirm board name, timezone, base URL. Pick your new-user policy.
- Community: rewrite the welcome bulletin in your own voice.
- Areas: rename the starter areas or build your own layout with categories.
- Themes / Editor: draw or import a logon screen.
- Leave the first oneliner. Boards feel alive when the walls have writing on them.
#What callers see
The terminal page is an 80 by 25 CP437 screen rendered with a real IBM VGA font. Menus respond to single hotkeys, prompts take a line of input, and a full-screen editor opens for message writing.
The clipboard works the terminal way: paste (Ctrl+V, Cmd+V, or the context menu) types into whatever accepts typing, a prompt line or the message editor, where pasted newlines become real line breaks. Drag-selecting any rectangle of the screen copies its text at mouse release, PuTTY style.
Keys echo (1.7.4). Press a hotkey and the character you typed prints at the cursor for the beat it takes the board to answer, the way a real terminal felt. The next screen paints over it, and a guard at the last column keeps a stray echo from ever scrolling the screen.
The cursor (1.7.3). The terminal keeps a classic blinking underscore at the resting position of every hotkey prompt: menus, pause lines, pagers, the whole logon tour. Before this, outside a typed-input field the prompts had no cursor at all, and a main menu only showed one where the board's own art happened to paint a blinking cell. It is drawn over the screen and never written into it, so art under the cursor survives untouched; typed fields keep the caret they already had, and a dead line shows nothing, as it should.
The matrix and new users
Before login: L to log in, A to apply, G to log off. Applications ask for handle, password, location, your custom question, and an optional email address; ENTER skips it. What happens next follows your new-user policy: approve (waits for you; the dashboard shows pending), auto (activates instantly), closed (no applications).
With outgoing mail configured (chapter 6), the matrix also answers R for a forgotten password. Since 1.6.0 it takes one press: right after a failed login, R sends the reset for the handle just tried, with no retyping. Pressed cold, it opens a small PASSWORD RESET screen asking "Reset for:" instead of bouncing back to the login line. Either way, if the account has an email on file, a single-use reset link (20-minute clock) goes out. The matrix answers the same sentence whether or not the account exists, one link per 15 minutes per account, and SysOp-level accounts are excluded on purpose (a SysOp handle is told so in as many words, so nobody waits on a letter that will never come). With mail off, R is not a key.
Nobody can park at the matrix, either: the idle hang-up (chapter 6) applies before login the same as after, so an abandoned tab stops holding a node.
The post-login sequence
The order is yours as of 1.7.3. Settings grew The logon tour: give each stop a position or turn it off, and the board walks your arrangement. Turn everything off and a caller lands straight at MAIN. Stops with nothing to say still skip themselves, as before, and two courtesies keep their seats whatever you arrange: the one-time email ask for an account with no address on file, and the mail check when letters are waiting. A board that never touches the setting runs the classic order below, unchanged.
Connect banner (optional modem ceremony; since 1.6.0 the CONNECT number matches the board's Line speed, CONNECT 9600 out of the box or CONNECT 14400 with the throttle off), logon art, a one-line email ask for accounts without one (ENTER skips), every unread bulletin oldest-first (a brand-new caller walks the whole history once; edits do not re-greet), the auto-message wall, a random rumor, mail check, last callers, then the MAIN menu. Any key advances.
The default menu map
| Key | Where |
|---|---|
| M | Message menu. Read, post, new scan, change area, mailbox. |
| C | Chat. The live room, everyone together. |
| D | Door games. HILO and Star Merchant. |
| I | Info desk. BBS list, board stats, bulletins. |
| P | People. User list, last callers, who's online. |
| O | Oneliners. The graffiti wall. |
| B | Bulletins. SysOp announcements. |
| Y | Your settings. Bell, connection speed, password. |
| G | Goodbye. Log off, with confirmation. |
Every menu, item and hotkey is editable in the menu designer.
Caller-side settings
Each caller gets a terminal bell toggle, a nostalgic connection-speed throttle (300, 1200, 2400 or 9600 baud, or off; keypresses drain the buffer instantly), a password change, and an [E]mail row to set, change or clear the address on their account. The mail room also answers S to flip between the inbox and the letters they have sent.
Two 1.6.0 notes on the throttle: new accounts start at the board's Line speed (chapter 6) instead of a hard-coded number, and the typing-out now genuinely covers everything. Changing message areas and the goodbye screen used to paint instantly; both now reveal at the wire speed like the rest of the board, and the line waits for the farewell to finish before dropping carrier.
Read marks are honest (1.6.1): because lists run newest-first, a caller often opens a fresh reply before an older message they have not seen. The read pointer used to leap over the older one and mark it read on the way past. Now each message is marked read when it is actually on the screen, the unread markers and the new-scan keep pointing at whatever was skipped, and the pointer catches up by itself once the gap is walked. Reading feels the same; the ledger simply stopped rounding up.
The message list (1.6.0): threads sort by their date, newest first, with replies always nested beneath their thread. Because the sort reads the date, a timestamp fixed from the console re-files the thread automatically. S in the list flips to oldest-first and the choice sticks to the account; unread messages are caught either way by the new-scan. List dates show the year. New in 1.7.0: Home and End jump to the top and the bottom of the list, and the command line under the list says so. Sorting keeps your place, and one press of Home puts you back at the top.
The area picker names what it highlights (1.7.0). As the highlight moves, the picker paints the highlighted board's description on its own quiet row. Boards that never filled a description in look exactly as before.
Long letters page (1.7.0). The mail room used to cut a letter off at the bottom of the screen; it now pages with N and P and a page indicator.
#The Dashboard
The console home page. Everything urgent surfaces here.
- Stat cards: calls today and ever; messages today; pending callers (with inline approve when your policy is approve); cron health in minutes since the last tick (a dash means it never ran).
- Who is online: every live node with handle, activity and idle time, plus three buttons per caller. Join chat drops you into the public room; Break in opens a private line to that caller (chapter 14); Log off (new in 1.6.0) hangs up that line. The caller sees "The SysOp has closed this line." and NO CARRIER, the node frees immediately, and the action lands in the admin log. It asks before it fires, and the line leaves the list the moment you confirm.
- The chat panel mirrors the room without you holding a node. The target selector aims your words: everyone in the public chat room, or a private line to one node. A banner above the box always shows where the next line goes, and a caller's page arrives with the form pre-aimed.
- Broadcast: type a message, pick minutes, and every connected caller sees it as a banner above their screen, whatever they are doing. Separate from chat; never lands in room history.
#Settings, every field
Identity
| Board name | Terminal title, banners, %BN in theme strings. |
| Base URL | Public address; used in generated links and cron advice. |
| Board number | What the connect ceremony dials; also %PH in theme
strings. Blank keeps the classic number derived from the board name. |
| Board timezone | The clock callers see everywhere; the daily-tick boundary. Storage stays UTC. |
Access
| Max nodes | Simultaneous callers (default 10). Past the cap: a busy screen, like a full modem bank. |
| New user policy | approve / auto / closed. |
| New user question | Your custom application question; answers land in the caller's note field. |
| BBS list additions | ACS for who may add directory entries (blank = everyone,
v = validated). Viewing is always open. |
| Banned addresses | One per line: an exact IP, a prefix ending in *
(203.0.113.*), or a # comment. A banned caller gets the
connect.banned theme string instead of a dial tone, before any session exists. A
ban landing mid-call drops the line on the next keystroke. |
| DOS doors | New in 1.7.0. The master switch for running original DOS door games (chapter 21). Off by default, and off means no console page, no menu action, and an API that answers 404: callers cannot tell the feature exists. |
| Board offline | New in 1.7.0. For maintenance days. Nobody can connect or log in, not even a SysOp account, until it flips back. New callers get a notice in your own words (pipe colors welcome; a stock line covers a blank box) and then the line drops. Callers already on stay on; a separate Disconnect everyone now button hangs up every line at once when the work needs the board empty. Every console page shows a reminder while the switch is on. |
| Prohibited words | New in 1.6.1. One word per line;
sysop ships on the list. A new application's handle is refused if it contains
any listed word anywhere, in any case: put test on the list and Test, Testicle
and Youtestit are all turned away. Nothing is retroactive, since the list is read only when a
new handle is typed, so existing accounts keep their names. |
Three prohibited names in a row ends the application: the board shows the caller the address
they are calling from, notes it in the security log, and drops the line. Any clean attempt in
between, even a malformed or already-taken one, resets the count. The refusal and the goodbye
are theme strings like everything else (nua.banned_handle,
nua.banned_bye, nua.banned_ip), so a themed board words its own
bouncer.
Display
| iCE colors | Bright backgrounds instead of blinking text. On if your art uses them. |
| Connect ceremony | The fake modem handshake on connect. Pure theater. |
| Allow user color | Callers may color their text with pipe codes in messages, mail, chat, oneliners, rumors and the auto-message. Off shows codes as typed. |
| Default theme | The theme every caller sees unless a specific one is set on their account (Users page). The everyday flow: duplicate default on the Themes page, edit the copy, pick it here. |
| The logon tour | New in 1.7.3. The order of the cards between the password and the main menu: welcome screen, unread bulletins, auto-message, rumor, last 10 callers. Give each stop a position or turn it off. Everything off means a caller lands straight at MAIN. The email ask and the mail check always keep their seats. |
| Line speed | New in 1.6.0. The board's default baud: 300, 1200, 2400, 9600, or "No throttle (CONNECT 14400)". New callers start here, the pre-login screen always types out at it, and the CONNECT banner shows the matching number. Default 9600. Dropping below that is charming to modem veterans and can read as broken to everyone else; the save reminds you. |
| Idle hang-up | New in 1.6.0. Minutes of caller silence before the board hangs up the line and frees the node, measured on keypresses rather than the browser's background polling, so an abandoned open tab cannot hold a node. Applies at every screen, the matrix included. Default 30; 0 disables. |
| SysOp chat style | New in 1.6.0. How break-ins and answered pages look on the caller's side: classic (one shared scroll) or split (the caller types in the top pane, your words fill the bottom, a labeled rule divides them). Default classic; the console side is the same either way. |
Outgoing mail
Send-only email through a mailbox you own. The board never reads a mailbox, and with the switch off (the default) it makes no outside connections at all.
| Outgoing mail | The master switch. Off hides every mail feature on the board. |
| Transport | smtp (host, port, STARTTLS or SSL, username, password)
or the hosting company's PHP mail(). |
| From address | What the letters are sent as; usually the mailbox you configured. |
| Send test | Proves the setup in one click; the result lands in the events log. |
What it unlocks: password resets from the matrix (R), the EMAILSYSOP menu action (callers write you a letter; replies go to their own email via Reply-To, one per caller per day), and the email question at application and logon. Every send lands in the events log. Caller emails are never verified, never shown to other callers, and visible only in the Users drawer.
SysOp notifications
New in 1.6.1, and strictly opt-in in the same way outgoing mail is: with no browser enabled, the board makes no outside connection for this at all. Enable it on a browser, desktop or phone, and a caller's page arrives as a real system push notification naming who is calling, which node, and the reason they gave, whether or not the console is open anywhere. Tapping it opens the console on their line, ready to answer.
- Standard Web Push, nothing borrowed. The board mints its own VAPID keys on first use and talks straight to the browser's push service. No libraries, no third-party account, no other party's JavaScript on your console.
- Enable as many browsers as you like, remove any of them from the same card, and send yourself a test ring to hear what a page feels like.
- Never in a caller's way. Pushes go out best-effort with short timeouts, so a push service having a bad day cannot slow the caller whose page is ringing. Dead subscriptions prune themselves.
The cron key
The Settings page shows the exact cron line for cPanel and a button to mint a new key. A new key invalidates the old one immediately; update your cron entry to match.
#Users and access
The list
Search by handle, filter by status, sort by any column; capped at 200 rows (narrow the search past that). Pending applications float up with one-click approve.
The edit drawer, field by field
| Level | 0 to 255. New callers start at 10; 255 is SysOp (console access, passes every ACS). |
| Flags | Twenty-six checkboxes, A to Z. Meaning is yours; ACS tests them with
fA and so on. |
| Status | active / pending / locked / deleted (soft; the row stays). |
| Location | Free text, shown in the user list and last callers. |
| Note | Private SysOp note; application answers land here. |
| The address password resets go to. Optional, never verified, never shown to callers; only you see it. | |
| Theme | Which theme this caller sees. |
| Last call | New in 1.7.0. Set a caller's last call date on the board clock, or clear it to never. For the SysOp bringing in decades of history whose callers should not all read as if they never called. |
| New password | Type once to reset; blank leaves it alone. |
The level ladder: 10 = fresh caller; 20 and up = yours to define; 100 = a handy
co-SysOp line (s100); 255 = SysOp.
#Access strings (ACS)
One tiny grammar controls visibility everywhere: areas (read and write separately), menu items, bulletins, voting questions, doors, menu backdrops. Blank always means everyone. Level 255 passes everything.
| Token | Passes when |
|---|---|
| s50 | Level 50 or higher. |
| fA | Caller has flag A. |
| v | Account is validated (active). |
| !fZ | NOT: caller lacks flag Z. |
| s50fB | Side by side = AND. |
| s50|fB | Pipe = OR. |
| (s50|fB)!fZ | Parentheses group. |
Recipes: v members only · s100 co-SysOps ·
fP flag-holders · s255 you alone.
A worked example
Access strings are easier to understand as a set than one at a time. Suppose fresh callers stay
at level 10, trusted regulars get bumped to 50, your co-SysOp sits at 100, and flag
P goes to anyone allowed in the private lounge.
Notice what each choice buys you. A blank read ACS means the area shows for everyone including
a pending application, which is usually right for a general board and never right for a private
one. Write s255 makes a read-only announcements area without a separate feature
for it. And because a failing caller never sees the line at all, the Lounge simply does not
exist for anyone without flag P: there is nothing to ask you about.
#Message areas and categories
Areas are the message bases. Categories are named shelves that group them: callers see each category as a header with its areas beneath, and the reader labels the area "Category / Area."
Categories
- Add (name up to 30 characters), rename inline, reorder with arrows. The caller list follows this order exactly.
- Delete: the category goes; its areas stay, loose. Nothing else is touched.
- Areas without a category gather under "Other Boards" at the end. A board with no categories shows the plain flat list.
Areas, field by field
| Tag | Short unique key, 2 to 12 characters (A to Z, digits, underscore), unique board-wide. |
| Name | Display name, up to 40 characters. |
| Description | One line under the name, up to 100 characters. |
| Category | The shelf it lists under, or none. |
| Read ACS | Who sees the area at all. |
| Write ACS | Who may post. Read-only announcements: write ACS
s255. |
| Listed | New in 1.6.5. Checked by default. Unchecked, the area leaves the general area-change list and nothing else. See below. |
- Arrows reorder an area within its own category (the order callers see).
- Delete refuses while the area holds messages; empty it first.
- The private mail spool is plumbing; the console will not let you edit or delete it.
Listed and unlisted areas
Every area has a Listed checkbox, checked by default. Uncheck it and the area disappears from the general area-change list, and from nowhere else. That is the flag's entire job.
An unlisted area still:
- counts its messages everywhere totals appear;
- shows up in the global new scan for any caller who passes its Read ACS. A caller with access deserves to hear about mail waiting for them;
- opens normally from any menu item that names it (chapter 10.4), from a category-filtered area change, or as a menu's default area;
- keeps serving a caller who was already reading it when it went unlisted.
#Themes
A theme is the board's wardrobe: every caller-visible string, plus which art gallery pieces dress the three big moments. The default theme is the board's permanent fallback and is never editable: not its strings, not its art. To change anything, Duplicate it and edit the copy; anything missing in your copy falls back to the built-in look, so you can never break the board permanently.
- Duplicate: copy any theme into an editable one under
data/themes/<name>. - Strings: every caller-facing string, grouped, with a live pipe-code preview. Saves
write your
strings.inioverlay. - Art: three bindings, connect (the pre-login screen), logon (the welcome), goodbye (the farewell). Each picks a piece from the art gallery, or "(generated default)" for the board's own drawing. Live previews render through the real terminal parser.
- Delete: blocked for the board's current default theme and while any caller wears it; deleting a copy of a shipped theme lets the shipped version show through.
- Export (1.6.0): every theme row but default has an Export link that downloads the
whole look as one self-contained
<name>.atdt-theme.json: strings, metadata, art bindings, and the art bytes themselves. Made for trading. The default theme is not exportable on purpose, since every board already ships it; duplicate it and export your copy. - Import a theme (1.6.0): the card at the bottom of the Themes page takes such a file and installs everything in one step. A taken theme name is uniqued (-2, -3 and so on). The art lands in the gallery with byte-level care: a piece identical to one already on the shelf is shared rather than duplicated, and a name clash with different bytes is renamed with the theme's bindings remapped to follow. An import can never overwrite art you already have, and the flash message says exactly what landed, what was shared and what was renamed.
- Which theme callers get: the Default theme picker in Settings covers everyone at once. A specific caller can be given a different theme in their edit drawer on the Users page ("(board default)" means they follow the Settings choice). New accounts follow the board default.
The everyday loop: duplicate default, edit your copy, set it as the board default in Settings. Done; every caller sees it.
The lists so far. 1.5.0: the mail-room pair (
mail.pick,
mail.pick_empty) and the settings prompt (set.prompt).
1.6.0: the matrix reset strings (matrix.reset_ask reworded;
reset_note, reset_sent_for, reset_sysop new), the
split-chat labels (sysopchat.split_top, split_bottom), and the
message-list command bar (list.commands, which now offers S to flip the
thread order). 1.6.1: the three application-desk strings
(nua.banned_handle, nua.banned_bye, nua.banned_ip).
1.6.5: two new denial strings for targeted areas. 1.7.0:
list.commands (it now mentions Home and End), nua.bad_handle (handles
may carry [ and ] now, a small courtesy to the C64 crowd), and the new
mail.read_more for the paged mail reader.Goodbye art, one note (1.5.5): the farewell piece now always paints on a cleared screen
and +++ NO CARRIER prints on row 25, so even a full-height goodbye keeps every
row.
#The ANSI editor and the art gallery
A full drawing program at Console › Editor: an 80 by 25 CP437 canvas rendered by
the same engine callers see. Everything it saves lands in the art gallery, one
board-wide shelf of .ans pieces under data/art/, and everywhere the
board can wear art picks from that same shelf by name.
Live text in art: type an MCI code into a piece with the Text tool and it expands when the art is displayed. "WELCOME TO %BN, %HN" on a logon screen greets every caller by name (Appendix B lists the codes). The substituted value shifts the rest of that row, so leave drawing room to the right of the code.
Tools
| Pencil (P) | Stamp the current glyph in current colors. |
| Half-block (B) | Paint 80x50-feel pixels; right-drag erases. |
| Text (T) | Click and type. |
| Font (O) | New in 1.5.5. Big ANSI letters, TheDraw style: pick a font, click, type. |
| Line (L) | Drag a straight run. |
| Rectangle (R) | Drag a border box. |
| Flood fill (F) | Fill a region. |
| Recolor (C) | New in 1.5.5. Repaint with the current ink; the characters stay put. |
| Select (S) | Drag, then Copy / Move / Tint / Blank. New in 1.5.5: Move and Copy lift the block visibly, steer with mouse or arrows (Shift moves by five), Enter or click places, Esc puts it back. |
- Palette: 16 foregrounds, 8 backgrounds (16 with iCE colors on).
- The glyph row holds the full CP437 set.
- Undo Ctrl+Z, redo Ctrl+Y; zoom and grid on the toolbar; Clear blanks the canvas (it asks first, and Undo brings it back).
- The canvas autosaves to your browser while you work.
Letter fonts
New in 1.5.5. The Font tool types words as large ANSI letters, the way TheDraw's
.TDF fonts did. Four fonts ship (Block, Block Wide, Block Shadow, Small), covering
A to Z and 0 to 9 and stamping in your current ink. Enter starts a new line,
Backspace steps back, and letters wrap like a typewriter.
Fonts... opens the font library, a small editor of its own: draw your own set glyph by
glyph (up to 16 wide by 8 tall, any colors, so your fonts stamp exactly as drawn), and it
appears in the Font picker alongside the shipped four. Stored as JSON under
data/fonts/; transparent cells leave whatever is under them alone.
The gallery
- Open: pick any piece off the shelf and edit it.
- Save to gallery: writes a real
.answith a SAUCE record under the name you give; anything bound to that name updates instantly. - Delete: takes a piece off the shelf; screens bound to it fall back to their generated look.
- Import: upload any
.ans(256 KB cap), including classic scene art with iCE backgrounds, then Save it to the gallery. - Export: download the exact bytes; PabloDraw and Moebius open them. Round trips are pixel-identical.
- The Gallery page (1.5.5): Console › Gallery shows every piece with a rendered preview, ten to a page, each with an Open-in-editor button. The dropdowns stay the fast path on a small shelf; this is the walk-the-aisles view for a big one.
Where pieces get used
| Connect / logon / goodbye | Themes page › Art: bind each slot to a piece. |
| Menu backdrop | Menus page: the Backdrop picker on the menu. |
| Per-level backdrops | Menus page: Backdrops by level (first ACS match wins). |
| ANSI bulletin | Community page: the art picker on the bulletin form. |
| ART menu item | The item's argument names the piece. |
#The community desk
One console page, six tabs, alphabetical on the rail; the page opens on Auto-message.
- Message boards (1.6.0): every category and board, listed the way a caller sees them, with live message counts. Open a board and every message is there, newest first, 25 to a page, with a one-click flip to oldest-first (the same date-driven order callers see, so a fixed timestamp re-files a message here too). You can edit the subject, the body, and the date and time stamp (entered in board time, stored UTC), and you can delete a message (soft, the same as caller-side deletes). Two things never change: who wrote it and where it sits in the reply tree. Those are facts of the record, shown read-only above the form. Private mail is a different matter entirely: mail areas are excluded from this tab at the query level. The console does not read anyone's letters.
- Bulletins: title (60 characters), body (pipe colors render; word-wrap at the full 80 columns), or an ANSI art slot shown full-screen instead. ACS per bulletin; sort orders the list; a fresh save greets every caller once at next logon. Anything updated since a caller's last visit is shown to them automatically; the key for browsing them at will is whatever your menu designer says it is.
- Oneliners / Rumors: callers write, you hold the eraser. One random rumor greets every logon; prune the duds.
- Voting booth: question (100 characters) plus 2 to 10 options and an optional ACS. One ballot per caller; bar-graph results. No editing once ballots exist: close (results only) or delete (ballots too).
- BBS list: the other-boards directory. Callers add (gated by the Settings ACS); you
edit and delete. Addresses must be
https://,telnet://, orhost:port. - Auto-message: one board-wide wall message shown at logon; callers who pass its ACS rewrite it from the caller side.
#Chat, break-in, paging and broadcast
- The room: one public channel, every node. History pages with PgUp and PgDn or the arrows; a half-typed line survives paging; timestamps show the board clock with dates across midnight. Long lines word-wrap onto up to three display rows instead of clipping at the right edge, so every typed character shows.
- Page SysOp: the caller pages with a reason; the console chat panel arrives pre-aimed at their node.
- Break in: from the dashboard, next to any caller. Opens the private line: the caller gets a bell and a banner naming you, and the private conversation interrupts whatever screen they are on (except mid-editor, where it politely waits so their draft survives, and lands the moment they finish). Everything on the private line is invisible to the room. ESC or Q returns the caller to what they were doing.
- The split screen (1.6.0): Settings offers a second style for the caller's side of a break-in or an answered page. In split, the caller keeps the top half of the screen for their own typing, your words fill the bottom half, and a dim rule with name tags divides the two: a proper old-style SysOp chat. Classic (one shared scroll) remains the default, the console side is identical either way, and the style is picked up fresh for each conversation.
- The room keeps its history (1.6.1): housekeeping used to sweep every chat line older than seven days, so a board with a slow week woke up to an empty room. The public room now keeps its newest 1,000 lines however old they are, and only the overflow past that cap is swept. Transient wire traffic (page requests, private SysOp lines and their hang-up markers) still expires after a week, as it should.
- Tidy the room (1.6.5): every public chat line on the console's live wire carries a delete link. One click and a confirm removes that line from the room for good, with an audit line in the admin log recording who said what. Pages and private SysOp traffic are working records; the link never appears on them, and the guard refuses them outright.
- Broadcast: a timed banner above every caller's screen for the minutes you choose. Never enters chat history.
#Door games in the console
The registry
Every door is one folder, and door folders live in the doors/ directory of your
ATDT installation, alongside the shipped games. If your board is at
www.example.com/atdt, a door called Dice Run is atdt/doors/dicerun/.
Scan reads that directory and registers what it finds.
Registering is all Scan does: no menu changes. To put a door in front of callers, use the Menus page like for anything else: add an item with the DOOR action, and every registered door is offered in the item's argument list automatically. Door entries are ordinary menu items: rename, re-key, reorder, hide or move them at will (the shipped DOORS menu's HILO and Star Merchant rows are just such items).
Per door here: enable or disable, display title, ACS, sort. A disabled door keeps any menu items but refuses to open; delete the item in Menus if you want it gone from the list too. A door whose folder went missing is flagged for re-upload or removal.
HILO
The number-guessing classic; no settings; its scoreboard feeds the Stats screen. Its source doubles as the SDK example.
Star Merchant
An original space-trading game in a persistent galaxy that generates itself the first time anyone opens the door. First-time players land on a two-page in-game primer; ? or H reopens it anywhere.
| Sectors | Galaxy size for the NEXT generation (takes effect on reset). Default 1000. |
| Turns per day | Daily action budget (default 250); the day-tick refills. |
| Combat | Master switch; off = purely economic galaxy. |
| Reset universe | Regenerates everything and erases every player. Type RESET to confirm. |
| Top merchants | The net-worth ladder. |
| Game log | Conquests, bounties, weekly ladder closes. |
What the day-tick does: port stocks drift 15 percent toward full; colonized planets produce by class; banks earn 0.5 percent; turns refill; fresh derelicts scatter; pirate crews drift one warp and respawn toward one per 50 sectors (never into Charter Space, sectors 1 to 9); weekly, the ladder snapshots into the hall of fame.
#The Door API
A door is one folder with a manifest and a PHP class. The board provides screen, input, storage and identity; the door returns frames. Nothing a door does can take the board down.
#Cron and the daily tick
The cron endpoint runs housekeeping. With a real cron entry it fires every five minutes; without one, pseudo-cron performs the same work piggybacked on caller traffic (it kicks in when the last tick is older than 15 minutes, guarded by a lock so only one request does it). Either way:
- Every tick: sweep dead sessions (nodes free up); prune events older than 90 days, and transient chat traffic older than 7 days. The public room keeps its newest 1,000 lines regardless of age (chapter 14).
- At board midnight (your timezone): each enabled door's
cron.php, thendata/logsrotation.
The cPanel line, printed by the installer and the Settings page:
The key guards the endpoint (cron.php?key=... over HTTP works too); wrong keys are
refused and logged. The dashboard card shows minutes since the last tick.
#Logs and events
| Events log | Everything notable, with a level. security covers login
lockouts on both surfaces; cron records ticks and failures; perf appears if a
response ever exceeds the 64 KB budget; door lines arrive tagged
door:<slug>. Hang-ups land here too (1.6.0): a console Log off and an idle
timeout each leave one line naming the node. Since 1.6.1, an applicant dropped for three
prohibited handles in a row leaves a security line naming their address. |
| Admin log | Every console action with who did it, so a co-SysOp's work is auditable. |
| Call log | One row per call with duration and a summary ("Posted 2 msgs, played HILO"). |
#Backups, upgrades and recovery
Backups
Everything that is yours lives in data/: configuration, the SQLite database, theme
overlays, the art gallery, your letter fonts, door storage. Back up that one folder and you have
the whole board (on MySQL, dump the database too). One thing sits outside it: a door you
installed yourself is code in doors/, so keep its zip or fold that folder into the
backup as well.
Upgrading in place
- Upload the new release's files over the old ones. The zip contains no
data/, so an overwrite upload cannot touch your data. - The first page hit migrates the database automatically if needed.
install.phpcoming back with the upload is harmless; it self-locks.
Skipping versions is fine. The migration is a single ladder keyed on the stored schema version: a board that missed a release (or five) climbs every rung it lacks, in order, on that same first hit. There is nothing to run by hand and no intermediate build to install; upgrading 1.0.0 to any future version is always the same overlay upload. The ladder runs under a lock so two simultaneous first-hits cannot collide, and the 1.1.0 rungs are safe to re-run if a crash interrupts them.
Recovering a lost SysOp password
With another level 255 account: reset it from the Users page. Without one: any database tool
(or a one-visit PHP snippet you delete after) setting users.pass_hash to the output
of PHP's password_hash() for your new password.
Troubleshooting
| Symptom | Cause and fix |
|---|---|
| Board looks broken after upgrade | Stale cached client from a very old build; one hard refresh fixes it forever. |
| Installer says already installed | By design. Delete
data/config.php only for a true wipe. |
| "Could not write" in the console | File permissions on data/. |
| Callers get BUSY | All nodes in use; raise Max nodes or wait for the sweep. |
| Menu will not go back to generated | A leftover per-level backdrop variant is outranking the picker. Chapter 10.3. |
| Cron card red | The cron entry stopped; re-check the line and key. Pseudo-cron keeps the board alive meanwhile. |
| Locked out of the console | Five failed logins in 15 minutes; wait out the window. |
#Networking (coming in v2)
This chapter will cover joining a network, subscribing to areas, reading poll logs, and diagnosing dead links.
#Pipe color codes
|00 to |15 foreground, |16 to |23
background, || a literal pipe. Callers can read this same table on the board
through a HELP menu item.
#MCI variables
These expand everywhere text is displayed, whoever typed them, SysOp or caller: theme strings,
messages and mail (bodies and subjects), bulletins, oneliners, rumors, the auto-message, chat,
BBS-list notes, the broadcast banner, and inside .ans art (the connect, logon and
goodbye screens, menu backdrops, ART items, and art bulletins).
Each viewer sees their own values; the stored text keeps the codes. Unknown %-pairs pass
through as typed. In art, a substituted value shifts the rest of its row, so leave drawing room
around the code; on the connect screen, before login, %HN reads "caller".
| %HN | The caller's handle |
| %LV | Level |
| %ND | Node |
| %BN | Board name |
| %PH | Board number |
| %DT | Date, board clock |
| %TM | Time, board clock |
| %CT | Calls today |
| %CA | Calls ever |
| %LC | Last caller |
| %UT | Total users |
| %AN | Current area name |
| %AD | Current area description. New in 1.7.0. |
| %MC | Messages in area |
| %VN | ATDT version |
| %BD | The viewer's connection speed: their own throttle if set, otherwise the board's Line speed. Reads FAST when the throttle is off. New in 1.6.0. |
#Settings quick reference
| Setting | Page · one line |
|---|---|
| Board name / Base URL / Timezone | Settings · identity and the caller clock. |
| Board number | Settings · the ceremony's dial string; %PH. |
| Max nodes | Settings · simultaneous caller cap (10). |
| New user policy / question | Settings · approve, auto, closed. |
| BBS list additions | Settings · ACS to add directory entries. |
| Banned addresses | Settings · IPs (exact or prefix) refused before the ceremony. |
| iCE colors | Settings · bright backgrounds vs blink. |
| Connect ceremony | Settings · the fake handshake. |
| Allow user color | Settings · caller pipe codes render. |
| Default theme | Settings · what everyone sees unless set per caller. |
| Line speed | Settings · board default baud; new callers start here; the CONNECT number. |
| Idle hang-up | Settings · quiet minutes before the line lets go, any screen (30; 0 off). |
| SysOp chat style | Settings · classic scroll or split screen, as the caller sees it. |
| Prohibited words | Settings · handles refused at the application desk; three in a row drops the line. |
| SysOp notifications | Settings · pages as browser push, opt-in per browser, HTTPS only. |
| Outgoing mail | Settings · send-only email: resets, EMAILSYSOP, the email asks. |
| Cron key | Settings · guards cron.php. |
| Theme (per caller) | Users · "(board default)" or a specific wardrobe. |
| Email (per caller) | Users · where that caller's password resets go. |
| The logon tour | Settings · the order of the cards after the password, or none at all. New in 1.7.3. |
| DOS doors | Settings · master switch for original DOS door games; off by default. New in 1.7.0. |
| Board offline | Settings · nobody connects, not even you, until it flips back. New in 1.7.0. |
| Last call (per caller) | Users · set or clear a caller's last call date. New in 1.7.0. |
| Listed | Areas · checked (default), the area appears in the general area-change list. Unchecked, it leaves that list and nothing else. Discovery, not security (9.3). New in 1.6.5. |
| Area scope | Menus · blank (default), this menu shares the board's current message area. A name: this menu keeps its own, shared with menus naming the same scope (10.4). New in 1.6.5. |
| Default area | Menus · the board a caller starts in the first time they read or post in this section. Blank: their first read shows the picker. Only meaningful with an Area scope. New in 1.6.5. |
| Area / Limit to category | Menus, item form · the item's second argument, shown only for read, post, newscan, setarea and setareaback (an area) and areachange (a category). See 10.2. New in 1.6.5. |
| Door enable / ACS / sort | Doors · which games, to whom, in what order. |
#What lives where
Back up data/. Everything else is replaceable from the release zip, except doors
you installed yourself.